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_framework.hxx"
26 
27 #include "framework/framelistanalyzer.hxx"
28 
29 //_______________________________________________
30 //	my own includes
31 #include <threadhelp/writeguard.hxx>
32 #include <threadhelp/readguard.hxx>
33 #include <targets.h>
34 #include <properties.h>
35 #include <services.h>
36 
37 //_______________________________________________
38 //	interface includes
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 #include <com/sun/star/frame/XModuleManager.hpp>
42 
43 //_______________________________________________
44 //	includes of other projects
45 #include <unotools/processfactory.hxx>
46 #include <vcl/svapp.hxx>
47 #include <tools/diagnose_ex.h>
48 
49 //_______________________________________________
50 //	namespace
51 
52 namespace framework{
53 
54 //_______________________________________________
55 //	non exported const
56 
57 //_______________________________________________
58 //	non exported definitions
59 
60 //_______________________________________________
61 //	declarations
62 
63 //_______________________________________________
64 
65 /**
66  */
67 
FrameListAnalyzer(const css::uno::Reference<css::frame::XFramesSupplier> & xSupplier,const css::uno::Reference<css::frame::XFrame> & xReferenceFrame,sal_uInt32 eDetectMode)68 FrameListAnalyzer::FrameListAnalyzer( const css::uno::Reference< css::frame::XFramesSupplier >& xSupplier       ,
69                                       const css::uno::Reference< css::frame::XFrame >&          xReferenceFrame ,
70                                             sal_uInt32                                          eDetectMode     )
71     : m_xSupplier      (xSupplier      )
72     , m_xReferenceFrame(xReferenceFrame)
73     , m_eDetectMode    (eDetectMode    )
74 {
75     impl_analyze();
76 }
77 
78 //_______________________________________________
79 
80 /**
81  */
82 
~FrameListAnalyzer()83 FrameListAnalyzer::~FrameListAnalyzer()
84 {
85 }
86 
87 //_______________________________________________
88 
89 /** returns an analyzed list of all currently opened (top!) frames inside the desktop tree.
90 
91     We try to get a snapshot of all opened frames, which are part of the desktop frame container.
92     Of course we can't access frames, which stands outside of this tree.
93     But it's necessary to collect top frames here only. Otherwise we interpret closing of last
94     frame wrong. Further we analyze this list and split into different parts.
95     E.g. for "CloseDoc" we must know, which frames of the given list referr to the same model.
96     These frames must be closed then. But all other frames must be untouched.
97     In case the request was "CloseWin" these splitted lists can be used too, to decide if the last window
98     or document was closed. Then we have to initialize the backing window ...
99     Last but not least we must know something about our special help frame. It must be handled
100     seperatly. And last but not least - the backing component frame must be detected too.
101 */
102 
impl_analyze()103 void FrameListAnalyzer::impl_analyze()
104 {
105     // reset all members to get a consistent state
106     m_bReferenceIsHidden  = sal_False;
107     m_bReferenceIsHelp    = sal_False;
108     m_bReferenceIsBacking = sal_False;
109     m_xHelp               = css::uno::Reference< css::frame::XFrame >();
110     m_xBackingComponent   = css::uno::Reference< css::frame::XFrame >();
111 
112     // try to get the task container by using the given supplier
113     css::uno::Reference< css::container::XIndexAccess > xFrameContainer(m_xSupplier->getFrames(), css::uno::UNO_QUERY);
114 
115     // All return list get an initial size to include all possible frames.
116     // They will be packed at the end of this method ... using the actual step positions then.
117     sal_Int32 nVisibleStep = 0;
118     sal_Int32 nHiddenStep  = 0;
119     sal_Int32 nModelStep   = 0;
120     sal_Int32 nCount       = xFrameContainer->getCount();
121 
122     m_lOtherVisibleFrames.realloc(nCount);
123     m_lOtherHiddenFrames.realloc(nCount);
124     m_lModelFrames.realloc(nCount);
125 
126     // ask for the model of the given reference frame.
127     // It must be compared with the model of every frame of the container
128     // to sort it into the list of frames with the same model.
129     // Suppress this step, if right detect mode isn't set.
130     css::uno::Reference< css::frame::XModel > xReferenceModel;
131     if ((m_eDetectMode & E_MODEL) == E_MODEL )
132     {
133         css::uno::Reference< css::frame::XController > xReferenceController;
134         if (m_xReferenceFrame.is())
135             xReferenceController = m_xReferenceFrame->getController();
136         if (xReferenceController.is())
137             xReferenceModel = xReferenceController->getModel();
138     }
139 
140     // check, if the reference frame is in hidden mode.
141     // But look, if this analyze step is really needed.
142     css::uno::Reference< css::beans::XPropertySet > xSet(m_xReferenceFrame, css::uno::UNO_QUERY);
143     if (
144         ((m_eDetectMode & E_HIDDEN) == E_HIDDEN) &&
145         (xSet.is()                             )
146        )
147     {
148         xSet->getPropertyValue(FRAME_PROPNAME_ISHIDDEN) >>= m_bReferenceIsHidden;
149     }
150 
151     // check, if the reference frame includes the backing component.
152     // But look, if this analyze step is really needed.
153     if (((m_eDetectMode & E_BACKINGCOMPONENT) == E_BACKINGCOMPONENT) && m_xReferenceFrame.is() )
154     {
155         try
156         {
157             css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::utl::getProcessServiceFactory();
158             css::uno::Reference< css::frame::XModuleManager > xModuleMgr(xSMGR->createInstance(SERVICENAME_MODULEMANAGER), css::uno::UNO_QUERY_THROW);
159             ::rtl::OUString sModule = xModuleMgr->identify(m_xReferenceFrame);
160             m_bReferenceIsBacking = (sModule.equals(SERVICENAME_STARTMODULE));
161         }
162         catch(const css::frame::UnknownModuleException&)
163         {
164         }
165         catch(const css::uno::Exception&)
166         {
167             DBG_UNHANDLED_EXCEPTION();
168         }
169     }
170 
171     // check, if the reference frame includes the help module.
172     // But look, if this analyze step is really needed.
173     if (
174         ((m_eDetectMode & E_HELP)     == E_HELP                ) &&
175         (m_xReferenceFrame.is()                                ) &&
176         (m_xReferenceFrame->getName() == SPECIALTARGET_HELPTASK)
177        )
178     {
179         m_bReferenceIsHelp = sal_True;
180     }
181 
182     try
183     {
184         // Step over all frames of the desktop frame container and analyze it.
185         for (sal_Int32 i=0; i<nCount; ++i)
186         {
187             // Ignore invalid items ... and of course the reference frame.
188             // It will be a member of the given frame list too - but it was already
189             // analyzed before!
190             css::uno::Reference< css::frame::XFrame > xFrame;
191             if (
192                 !(xFrameContainer->getByIndex(i) >>= xFrame) ||
193                 !(xFrame.is()                              ) ||
194                  (xFrame==m_xReferenceFrame                )
195                )
196                 continue;
197 
198             #ifdef ENABLE_WARNINGS
199             if (
200                 ((m_eDetectMode & E_ZOMBIE) == E_ZOMBIE) &&
201                 (
202                  (!xFrame->getContainerWindow().is()) ||
203                  (!xFrame->getComponentWindow().is())
204                 )
205                )
206             {
207                 LOG_WARNING("FrameListAnalyzer::impl_analyze()", "ZOMBIE!")
208             }
209             #endif
210 
211             // -------------------------------------------------
212             // a) Is it the special help task?
213             //    Return it separated from any return list.
214             if (
215                 ((m_eDetectMode & E_HELP) == E_HELP      ) &&
216                 (xFrame->getName()==SPECIALTARGET_HELPTASK)
217                )
218             {
219                 m_xHelp = xFrame;
220                 continue;
221             }
222 
223             // -------------------------------------------------
224             // b) Or is includes this task the special backing component?
225             //    Return it separated from any return list.
226             //    But check if the reference task itself is the backing frame.
227             //    Our user mst know it to decide right.
228             if ((m_eDetectMode & E_BACKINGCOMPONENT) == E_BACKINGCOMPONENT)
229             {
230                 try
231                 {
232                     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = ::utl::getProcessServiceFactory();
233                     css::uno::Reference< css::frame::XModuleManager > xModuleMgr(xSMGR->createInstance(SERVICENAME_MODULEMANAGER), css::uno::UNO_QUERY);
234                     ::rtl::OUString sModule = xModuleMgr->identify(xFrame);
235                     if (sModule.equals(SERVICENAME_STARTMODULE))
236                     {
237                         m_xBackingComponent = xFrame;
238                         continue;
239                     }
240                 }
241                 catch(const css::uno::Exception&)
242                     {}
243             }
244 
245             // -------------------------------------------------
246             // c) Or is it the a task, which uses the specified model?
247             //    Add it to the list of "model frames".
248             if ((m_eDetectMode & E_MODEL) == E_MODEL)
249             {
250                 css::uno::Reference< css::frame::XController > xController = xFrame->getController();
251                 css::uno::Reference< css::frame::XModel >      xModel      ;
252                 if (xController.is())
253                     xModel = xController->getModel();
254                 if (xModel==xReferenceModel)
255                 {
256                     m_lModelFrames[nModelStep] = xFrame;
257                     ++nModelStep;
258                     continue;
259                 }
260             }
261 
262             // -------------------------------------------------
263             // d) Or is it the a task, which use another or no model at all?
264             //    Add it to the list of "other frames". But look for it's
265             //    visible state ... if it's allowed to do so.
266             // -------------------------------------------------
267             sal_Bool bHidden = sal_False;
268             if ((m_eDetectMode & E_HIDDEN) == E_HIDDEN )
269             {
270                 xSet = css::uno::Reference< css::beans::XPropertySet >(xFrame, css::uno::UNO_QUERY);
271                 if (xSet.is())
272                 {
273                     xSet->getPropertyValue(FRAME_PROPNAME_ISHIDDEN) >>= bHidden;
274                 }
275             }
276 
277             if (bHidden)
278             {
279                 m_lOtherHiddenFrames[nHiddenStep] = xFrame;
280                 ++nHiddenStep;
281             }
282             else
283             {
284                 m_lOtherVisibleFrames[nVisibleStep] = xFrame;
285                 ++nVisibleStep;
286             }
287         }
288     }
289     catch(css::lang::IndexOutOfBoundsException)
290     {
291         // stop copying if index seems to be wrong.
292         // This interface can't really guarantee its count for multithreaded
293         // environments. So it can occur!
294     }
295 
296     // Pack both lists by using the actual step positions.
297     // All empty or ignorable items should exist at the end of these lists
298     // behind the position pointers. So they will be removed by a reallocation.
299     m_lOtherVisibleFrames.realloc(nVisibleStep);
300     m_lOtherHiddenFrames.realloc(nHiddenStep);
301     m_lModelFrames.realloc(nModelStep);
302 }
303 
304 } //  namespace framework
305