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_framework.hxx"
30 
31 //_________________________________________________________________________________________________________________
32 //	my own includes
33 //_________________________________________________________________________________________________________________
34 #include <pattern/window.hxx>
35 #include <helper/persistentwindowstate.hxx>
36 #include <threadhelp/writeguard.hxx>
37 #include <threadhelp/readguard.hxx>
38 #include <macros/generic.hxx>
39 #include <services.h>
40 
41 //_________________________________________________________________________________________________________________
42 //	interface includes
43 //_________________________________________________________________________________________________________________
44 #include <com/sun/star/awt/XWindow.hpp>
45 
46 #ifndef _COM_SUN_STAR_LANG_XSERVICXEINFO_HPP_
47 #include <com/sun/star/lang/XServiceInfo.hpp>
48 #endif
49 #include <com/sun/star/lang/IllegalArgumentException.hpp>
50 #include <com/sun/star/frame/XModuleManager.hpp>
51 
52 //_________________________________________________________________________________________________________________
53 //	other includes
54 //_________________________________________________________________________________________________________________
55 #include <comphelper/configurationhelper.hxx>
56 #include <vcl/window.hxx>
57 #include <vcl/syswin.hxx>
58 
59 #ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
60 #include <toolkit/unohlp.hxx>
61 #endif
62 #include <vcl/svapp.hxx>
63 #include <vcl/wrkwin.hxx>
64 #include <rtl/string.hxx>
65 
66 //_________________________________________________________________________________________________________________
67 //	namespace
68 
69 namespace framework{
70 
71 //_________________________________________________________________________________________________________________
72 //	definitions
73 
74 //*****************************************************************************************************************
75 //  XInterface, XTypeProvider
76 
77 DEFINE_XINTERFACE_4(PersistentWindowState                                                       ,
78                     OWeakObject                                                                 ,
79                     DIRECT_INTERFACE (css::lang::XTypeProvider                                  ),
80                     DIRECT_INTERFACE (css::lang::XInitialization                                ),
81                     DIRECT_INTERFACE (css::frame::XFrameActionListener                          ),
82                     DERIVED_INTERFACE(css::lang::XEventListener,css::frame::XFrameActionListener))
83 
84 DEFINE_XTYPEPROVIDER_4(PersistentWindowState           ,
85                        css::lang::XTypeProvider        ,
86                        css::lang::XInitialization      ,
87                        css::frame::XFrameActionListener,
88                        css::lang::XEventListener       )
89 
90 //*****************************************************************************************************************
91 PersistentWindowState::PersistentWindowState(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
92     : ThreadHelpBase          (&Application::GetSolarMutex())
93     , m_xSMGR                 (xSMGR                        )
94     , m_bWindowStateAlreadySet(sal_False                    )
95 {
96 }
97 
98 //*****************************************************************************************************************
99 PersistentWindowState::~PersistentWindowState()
100 {
101 }
102 
103 //*****************************************************************************************************************
104 void SAL_CALL PersistentWindowState::initialize(const css::uno::Sequence< css::uno::Any >& lArguments)
105     throw(css::uno::Exception       ,
106           css::uno::RuntimeException)
107 {
108     // check arguments
109     css::uno::Reference< css::frame::XFrame > xFrame;
110     if (lArguments.getLength() < 1)
111         throw css::lang::IllegalArgumentException(
112                 DECLARE_ASCII("Empty argument list!"),
113                 static_cast< ::cppu::OWeakObject* >(this),
114                 1);
115 
116     lArguments[0] >>= xFrame;
117     if (!xFrame.is())
118         throw css::lang::IllegalArgumentException(
119                 DECLARE_ASCII("No valid frame specified!"),
120                 static_cast< ::cppu::OWeakObject* >(this),
121                 1);
122 
123     // SAFE -> ----------------------------------
124     WriteGuard aWriteLock(m_aLock);
125     // hold the frame as weak reference(!) so it can die everytimes :-)
126     m_xFrame = xFrame;
127     aWriteLock.unlock();
128     // <- SAFE ----------------------------------
129 
130     // start listening
131     xFrame->addFrameActionListener(this);
132 }
133 
134 //*****************************************************************************************************************
135 void SAL_CALL PersistentWindowState::frameAction(const css::frame::FrameActionEvent& aEvent)
136     throw(css::uno::RuntimeException)
137 {
138     // SAFE -> ----------------------------------
139     ReadGuard aReadLock(m_aLock);
140     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR ;
141     css::uno::Reference< css::frame::XFrame >              xFrame(m_xFrame.get(), css::uno::UNO_QUERY);
142     sal_Bool                                               bRestoreWindowState = !m_bWindowStateAlreadySet;
143     aReadLock.unlock();
144     // <- SAFE ----------------------------------
145 
146     // frame already gone ? We hold it weak only ...
147     if (!xFrame.is())
148         return;
149 
150     // no window -> no position and size available
151     css::uno::Reference< css::awt::XWindow > xWindow = xFrame->getContainerWindow();
152     if (!xWindow.is())
153         return;
154 
155     // unknown module -> no configuration available!
156     ::rtl::OUString sModuleName = PersistentWindowState::implst_identifyModule(xSMGR, xFrame);
157     if (!sModuleName.getLength())
158         return;
159 
160     switch(aEvent.Action)
161     {
162         case css::frame::FrameAction_COMPONENT_ATTACHED :
163             {
164                 if (bRestoreWindowState)
165                 {
166                     ::rtl::OUString sWindowState = PersistentWindowState::implst_getWindowStateFromConfig(xSMGR, sModuleName);
167                     PersistentWindowState::implst_setWindowStateOnWindow(xWindow,sWindowState);
168                     // SAFE -> ----------------------------------
169                     WriteGuard aWriteLock(m_aLock);
170                     m_bWindowStateAlreadySet = sal_True;
171                     aWriteLock.unlock();
172                     // <- SAFE ----------------------------------
173                 }
174             }
175             break;
176 
177         case css::frame::FrameAction_COMPONENT_REATTACHED :
178             {
179                 // nothing todo here, because its not allowed to change position and size
180                 // of an alredy existing frame!
181             }
182             break;
183 
184         case css::frame::FrameAction_COMPONENT_DETACHING :
185             {
186                 ::rtl::OUString sWindowState = PersistentWindowState::implst_getWindowStateFromWindow(xWindow);
187                 PersistentWindowState::implst_setWindowStateOnConfig(xSMGR, sModuleName, sWindowState);
188             }
189             break;
190         default:
191             break;
192     }
193 }
194 
195 //*****************************************************************************************************************
196 void SAL_CALL PersistentWindowState::disposing(const css::lang::EventObject&)
197     throw(css::uno::RuntimeException)
198 {
199     // nothing todo here - because we hold the frame as weak reference only
200 }
201 
202 //*****************************************************************************************************************
203 ::rtl::OUString PersistentWindowState::implst_identifyModule(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR ,
204                                                              const css::uno::Reference< css::frame::XFrame >&              xFrame)
205 {
206     ::rtl::OUString sModuleName;
207 
208     css::uno::Reference< css::frame::XModuleManager > xModuleManager(
209         xSMGR->createInstance(SERVICENAME_MODULEMANAGER),
210         css::uno::UNO_QUERY_THROW);
211 
212     try
213     {
214         sModuleName = xModuleManager->identify(xFrame);
215     }
216     catch(const css::uno::RuntimeException& exRun)
217         { throw exRun; }
218     catch(const css::uno::Exception&)
219         { sModuleName = ::rtl::OUString(); }
220 
221     return sModuleName;
222 }
223 
224 //*****************************************************************************************************************
225 ::rtl::OUString PersistentWindowState::implst_getWindowStateFromConfig(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR      ,
226                                                                        const ::rtl::OUString&                                        sModuleName)
227 {
228     ::rtl::OUString sWindowState;
229 
230     ::rtl::OUStringBuffer sRelPathBuf(256);
231     sRelPathBuf.appendAscii("Office/Factories/*[\"");
232     sRelPathBuf.append     (sModuleName            );
233     sRelPathBuf.appendAscii("\"]"                  );
234 
235     ::rtl::OUString sPackage = ::rtl::OUString::createFromAscii("org.openoffice.Setup/");
236     ::rtl::OUString sRelPath = sRelPathBuf.makeStringAndClear();
237     ::rtl::OUString sKey     = ::rtl::OUString::createFromAscii("ooSetupFactoryWindowAttributes");
238 
239     try
240     {
241         ::comphelper::ConfigurationHelper::readDirectKey(xSMGR,
242                                                                                       sPackage,
243                                                                                       sRelPath,
244                                                                                       sKey,
245                                                                                       ::comphelper::ConfigurationHelper::E_READONLY) >>= sWindowState;
246     }
247     catch(const css::uno::RuntimeException& exRun)
248         { throw exRun; }
249     catch(const css::uno::Exception&)
250         { sWindowState = ::rtl::OUString(); }
251 
252     return sWindowState;
253 }
254 
255 //*****************************************************************************************************************
256 void PersistentWindowState::implst_setWindowStateOnConfig(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR       ,
257                                                           const ::rtl::OUString&                                        sModuleName ,
258                                                           const ::rtl::OUString&                                        sWindowState)
259 {
260     ::rtl::OUStringBuffer sRelPathBuf(256);
261     sRelPathBuf.appendAscii("Office/Factories/*[\"");
262     sRelPathBuf.append     (sModuleName            );
263     sRelPathBuf.appendAscii("\"]"                  );
264 
265     ::rtl::OUString sPackage = ::rtl::OUString::createFromAscii("org.openoffice.Setup/");
266     ::rtl::OUString sRelPath = sRelPathBuf.makeStringAndClear();
267     ::rtl::OUString sKey     = ::rtl::OUString::createFromAscii("ooSetupFactoryWindowAttributes");
268 
269     try
270     {
271         ::comphelper::ConfigurationHelper::writeDirectKey(xSMGR,
272                                                           sPackage,
273                                                           sRelPath,
274                                                           sKey,
275                                                           css::uno::makeAny(sWindowState),
276                                                           ::comphelper::ConfigurationHelper::E_STANDARD);
277     }
278     catch(const css::uno::RuntimeException& exRun)
279         { throw exRun; }
280     catch(const css::uno::Exception&)
281         {}
282 }
283 
284 //*****************************************************************************************************************
285 ::rtl::OUString PersistentWindowState::implst_getWindowStateFromWindow(const css::uno::Reference< css::awt::XWindow >& xWindow)
286 {
287     ::rtl::OUString sWindowState;
288 
289     if (xWindow.is())
290     {
291         // SOLAR SAFE -> ------------------------
292         ::vos::OClearableGuard aSolarLock(Application::GetSolarMutex());
293 
294         Window* pWindow = VCLUnoHelper::GetWindow(xWindow);
295         // check for system window is neccessary to guarantee correct pointer cast!
296         if (
297             (pWindow                  ) &&
298             (pWindow->IsSystemWindow())
299            )
300         {
301             sal_uLong nMask  =   WINDOWSTATE_MASK_ALL;
302                   nMask &= ~(WINDOWSTATE_MASK_MINIMIZED);
303             sWindowState = B2U_ENC(
304                             ((SystemWindow*)pWindow)->GetWindowState(nMask),
305                             RTL_TEXTENCODING_UTF8);
306         }
307 
308         aSolarLock.clear();
309         // <- SOLAR SAFE ------------------------
310     }
311 
312     return sWindowState;
313 }
314 
315 
316 //*********************************************************************************************************
317 void PersistentWindowState::implst_setWindowStateOnWindow(const css::uno::Reference< css::awt::XWindow >& xWindow     ,
318                                                           const ::rtl::OUString&                          sWindowState)
319 {
320     if (
321         (!xWindow.is()                ) ||
322         ( sWindowState.getLength() < 1)
323        )
324         return;
325 
326     // SOLAR SAFE -> ------------------------
327     ::vos::OClearableGuard aSolarLock(Application::GetSolarMutex());
328 
329     Window* pWindow = VCLUnoHelper::GetWindow(xWindow);
330     if (!pWindow)
331         return;
332 
333     // check for system and work window - its neccessary to guarantee correct pointer cast!
334     sal_Bool bSystemWindow = pWindow->IsSystemWindow();
335     sal_Bool bWorkWindow   = (pWindow->GetType() == WINDOW_WORKWINDOW);
336 
337     if (!bSystemWindow && !bWorkWindow)
338         return;
339 
340     SystemWindow* pSystemWindow = (SystemWindow*)pWindow;
341     WorkWindow*   pWorkWindow   = (WorkWindow*  )pWindow;
342 
343     // dont save this special state!
344     if (pWorkWindow->IsMinimized())
345         return;
346 
347     ::rtl::OUString sOldWindowState = ::rtl::OStringToOUString( pSystemWindow->GetWindowState(), RTL_TEXTENCODING_ASCII_US );
348     if ( sOldWindowState != sWindowState )
349         pSystemWindow->SetWindowState(U2B_ENC(sWindowState,RTL_TEXTENCODING_UTF8));
350 
351     aSolarLock.clear();
352     // <- SOLAR SAFE ------------------------
353 }
354 
355 } // namespace framework
356