1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <assert.h>
21 #include <stdlib.h>
22 
23 #include <sal/log.hxx>
24 
25 #include <tools/stream.hxx>
26 
27 #include <sfx2/module.hxx>
28 #include <sfx2/objface.hxx>
29 #include <sfx2/msg.hxx>
30 #include <sfx2/app.hxx>
31 #include <sfx2/msgpool.hxx>
32 #include <sfx2/objsh.hxx>
33 #include <rtl/strbuf.hxx>
34 
35 extern "C" {
36 
37 static int
SfxCompareSlots_qsort(const void * pSmaller,const void * pBigger)38 SfxCompareSlots_qsort( const void* pSmaller, const void* pBigger )
39 {
40     return static_cast<int>(static_cast<SfxSlot const *>(pSmaller)->GetSlotId()) -
41            static_cast<int>(static_cast<SfxSlot const *>(pBigger)->GetSlotId());
42 }
43 
44 static int
SfxCompareSlots_bsearch(const void * pSmaller,const void * pBigger)45 SfxCompareSlots_bsearch( const void* pSmaller, const void* pBigger )
46 {
47     return static_cast<int>(*static_cast<sal_uInt16 const *>(pSmaller)) -
48            static_cast<int>(static_cast<SfxSlot const *>(pBigger)->GetSlotId());
49 }
50 
51 }
52 
53 struct SfxObjectUI_Impl
54 {
55     sal_uInt16 const         nPos;
56     SfxVisibilityFlags const nFlags;
57     sal_uInt32 const         nObjId;
58     bool                     bContext;
59     SfxShellFeature const    nFeature;
60 
SfxObjectUI_ImplSfxObjectUI_Impl61     SfxObjectUI_Impl(sal_uInt16 n, SfxVisibilityFlags f, sal_uInt32 nId, SfxShellFeature nFeat) :
62         nPos(n),
63         nFlags(f),
64         nObjId(nId),
65         bContext(false),
66         nFeature(nFeat)
67     {
68     }
69 };
70 
71 struct SfxInterface_Impl
72 {
73     std::vector<std::unique_ptr<SfxObjectUI_Impl>>
74                             aObjectBars;    // registered ObjectBars
75     std::vector<std::unique_ptr<SfxObjectUI_Impl>>
76                             aChildWindows;  // registered ChildWindows
77     OUString                aPopupName;     // registered PopupMenu
78     StatusBarId             eStatBarResId;  // registered StatusBar
79     SfxModule*              pModule;
80     bool                    bRegistered;
81 
SfxInterface_ImplSfxInterface_Impl82     SfxInterface_Impl()
83         : eStatBarResId(StatusBarId::None)
84         , pModule(nullptr)
85         , bRegistered(false)
86     {
87     }
88 };
89 
90 static SfxObjectUI_Impl* CreateObjectBarUI_Impl(sal_uInt16 nPos, SfxVisibilityFlags nFlags, ToolbarId eId, SfxShellFeature nFeature);
91 
92 // constructor, registers a new unit
SfxInterface(const char * pClassName,bool bUsableSuperClass,SfxInterfaceId nId,const SfxInterface * pParent,SfxSlot & rSlotMap,sal_uInt16 nSlotCount)93 SfxInterface::SfxInterface( const char *pClassName,
94                             bool bUsableSuperClass,
95                             SfxInterfaceId nId,
96                             const SfxInterface* pParent,
97                             SfxSlot &rSlotMap, sal_uInt16 nSlotCount ):
98     pName(pClassName),
99     pGenoType(pParent),
100     nClassId(nId),
101     bSuperClass(bUsableSuperClass),
102     pImplData(new SfxInterface_Impl)
103 {
104     SetSlotMap( rSlotMap, nSlotCount );
105 }
106 
Register(SfxModule * pMod)107 void SfxInterface::Register( SfxModule* pMod )
108 {
109     pImplData->bRegistered = true;
110     pImplData->pModule = pMod;
111     if ( pMod )
112         pMod->GetSlotPool()->RegisterInterface(*this);
113     else
114         SfxGetpApp()->GetAppSlotPool_Impl().RegisterInterface(*this);
115 }
116 
SetSlotMap(SfxSlot & rSlotMap,sal_uInt16 nSlotCount)117 void SfxInterface::SetSlotMap( SfxSlot& rSlotMap, sal_uInt16 nSlotCount )
118 {
119     pSlots = &rSlotMap;
120     nCount = nSlotCount;
121     SfxSlot* pIter = pSlots;
122     if ( 1 == nCount && !pIter->pNextSlot )
123         pIter->pNextSlot = pIter;
124 
125     if ( !pIter->pNextSlot )
126     {
127         // sort the SfxSlots by id
128         qsort( pSlots, nCount, sizeof(SfxSlot), SfxCompareSlots_qsort );
129 
130         // link masters and slaves
131         sal_uInt16 nIter = 1;
132         for ( pIter = pSlots; nIter <= nCount; ++pIter, ++nIter )
133         {
134 
135             assert( nIter == nCount ||
136                     pIter->GetSlotId() != (pIter+1)->GetSlotId() );
137 
138             if ( nullptr == pIter->GetNextSlot() )
139             {
140                 // Slots referring in circle to the next with the same
141                 // Status method.
142                 SfxSlot *pLastSlot = pIter;
143                 for ( sal_uInt16 n = nIter; n < Count(); ++n )
144                 {
145                     SfxSlot *pCurSlot = pSlots+n;
146                     if ( pCurSlot->GetStateFnc() == pIter->GetStateFnc() )
147                     {
148                         pLastSlot->pNextSlot = pCurSlot;
149                         pLastSlot = pCurSlot;
150                     }
151                 }
152                 pLastSlot->pNextSlot = pIter;
153             }
154         }
155     }
156 #ifdef DBG_UTIL
157     else
158     {
159         sal_uInt16 nIter = 1;
160         for ( SfxSlot *pNext = pIter+1; nIter < nCount; ++pNext, ++nIter )
161         {
162 
163             if ( pNext->GetSlotId() <= pIter->GetSlotId() )
164                 SAL_WARN( "sfx.control", "Wrong order" );
165 
166             const SfxSlot *pCurSlot = pIter;
167             do
168             {
169                 pCurSlot = pCurSlot->pNextSlot;
170                 if ( pCurSlot->GetStateFnc() != pIter->GetStateFnc() )
171                 {
172                     SAL_WARN("sfx.control", "Linked Slots with different State Methods : "
173                                 << pCurSlot->GetSlotId()
174                                 << " , " << pIter->GetSlotId() );
175                 }
176             }
177             while ( pCurSlot != pIter );
178 
179             pIter = pNext;
180         }
181     }
182 #endif
183 }
184 
185 
~SfxInterface()186 SfxInterface::~SfxInterface()
187 {
188     SfxModule *pMod = pImplData->pModule;
189     bool bRegistered = pImplData->bRegistered;
190     assert( bRegistered );
191     if ( bRegistered )
192     {
193         if ( pMod )
194         {
195             // can return nullptr if we are called from the SfxSlotPool destructor
196             if (pMod->GetSlotPool())
197                 pMod->GetSlotPool()->ReleaseInterface(*this);
198         }
199         else
200             SfxGetpApp()->GetAppSlotPool_Impl().ReleaseInterface(*this);
201     }
202 }
203 
204 
205 // searches for the specified func
206 
GetSlot(sal_uInt16 nFuncId) const207 const SfxSlot* SfxInterface::GetSlot( sal_uInt16 nFuncId ) const
208 {
209 
210     assert( pSlots );
211     assert( nCount );
212 
213     // find the id using binary search
214     void* p = bsearch( &nFuncId, pSlots, nCount, sizeof(SfxSlot),
215                        SfxCompareSlots_bsearch );
216     if ( !p && pGenoType )
217         return pGenoType->GetSlot( nFuncId );
218 
219     return static_cast<const SfxSlot*>(p);
220 }
221 
GetSlot(const OUString & rCommand) const222 const SfxSlot* SfxInterface::GetSlot( const OUString& rCommand ) const
223 {
224     static const char UNO_COMMAND[] = ".uno:";
225 
226     OUString aCommand( rCommand );
227     if ( aCommand.startsWith( UNO_COMMAND ) )
228          aCommand = aCommand.copy( sizeof( UNO_COMMAND )-1 );
229 
230     for ( sal_uInt16 n=0; n<nCount; n++ )
231     {
232         if ( (pSlots+n)->pUnoName &&
233              aCommand.compareToIgnoreAsciiCaseAscii( (pSlots+n)->GetUnoName() ) == 0 )
234             return pSlots+n;
235     }
236 
237     return pGenoType ? pGenoType->GetSlot( aCommand ) : nullptr;
238 }
239 
240 
GetRealSlot(const SfxSlot * pSlot) const241 const SfxSlot* SfxInterface::GetRealSlot( const SfxSlot *pSlot ) const
242 {
243 
244     assert( pSlots );
245     assert( nCount );
246 
247     if ( !ContainsSlot_Impl(pSlot) )
248     {
249         if(pGenoType)
250             return pGenoType->GetRealSlot(pSlot);
251         SAL_WARN( "sfx.control", "unknown Slot" );
252         return nullptr;
253     }
254 
255     return nullptr;
256 }
257 
258 
RegisterPopupMenu(const OUString & rResourceName)259 void SfxInterface::RegisterPopupMenu( const OUString& rResourceName )
260 {
261     pImplData->aPopupName = rResourceName;
262 }
263 
RegisterObjectBar(sal_uInt16 nPos,SfxVisibilityFlags nFlags,ToolbarId eId)264 void SfxInterface::RegisterObjectBar(sal_uInt16 nPos, SfxVisibilityFlags nFlags, ToolbarId eId)
265 {
266     RegisterObjectBar(nPos, nFlags, eId, SfxShellFeature::NONE);
267 }
268 
RegisterObjectBar(sal_uInt16 nPos,SfxVisibilityFlags nFlags,ToolbarId eId,SfxShellFeature nFeature)269 void SfxInterface::RegisterObjectBar(sal_uInt16 nPos, SfxVisibilityFlags nFlags, ToolbarId eId, SfxShellFeature nFeature)
270 {
271     SfxObjectUI_Impl* pUI = CreateObjectBarUI_Impl(nPos, nFlags, eId, nFeature);
272     if ( pUI )
273         pImplData->aObjectBars.emplace_back(pUI);
274 }
275 
CreateObjectBarUI_Impl(sal_uInt16 nPos,SfxVisibilityFlags nFlags,ToolbarId eId,SfxShellFeature nFeature)276 SfxObjectUI_Impl* CreateObjectBarUI_Impl(sal_uInt16 nPos, SfxVisibilityFlags nFlags, ToolbarId eId, SfxShellFeature nFeature)
277 {
278     if (nFlags == SfxVisibilityFlags::Invisible)
279         nFlags |= SfxVisibilityFlags::Standard;
280 
281     return new SfxObjectUI_Impl(nPos, nFlags, static_cast<sal_uInt32>(eId), nFeature);
282 }
283 
GetObjectBarId(sal_uInt16 nNo) const284 ToolbarId SfxInterface::GetObjectBarId(sal_uInt16 nNo) const
285 {
286     bool bGenoType = (pGenoType != nullptr && pGenoType->UseAsSuperClass());
287     if ( bGenoType )
288     {
289         // Are there toolbars in the super class?
290         sal_uInt16 nBaseCount = pGenoType->GetObjectBarCount();
291         if ( nNo < nBaseCount )
292             // The Super class comes first
293             return pGenoType->GetObjectBarId(nNo);
294         else
295             nNo = nNo - nBaseCount;
296     }
297 
298     assert( nNo<pImplData->aObjectBars.size() );
299 
300     return static_cast<ToolbarId>(pImplData->aObjectBars[nNo]->nObjId);
301 }
302 
GetObjectBarPos(sal_uInt16 nNo) const303 sal_uInt16 SfxInterface::GetObjectBarPos( sal_uInt16 nNo ) const
304 {
305     bool bGenoType = (pGenoType != nullptr && pGenoType->UseAsSuperClass());
306     if ( bGenoType )
307     {
308         // Are there toolbars in the super class?
309         sal_uInt16 nBaseCount = pGenoType->GetObjectBarCount();
310         if ( nNo < nBaseCount )
311             // The Super class comes first
312             return pGenoType->GetObjectBarPos( nNo );
313         else
314             nNo = nNo - nBaseCount;
315     }
316 
317     assert( nNo<pImplData->aObjectBars.size() );
318 
319     return pImplData->aObjectBars[nNo]->nPos;
320 }
321 
GetObjectBarFlags(sal_uInt16 nNo) const322 SfxVisibilityFlags SfxInterface::GetObjectBarFlags( sal_uInt16 nNo ) const
323 {
324     bool bGenoType = (pGenoType != nullptr && pGenoType->UseAsSuperClass());
325     if ( bGenoType )
326     {
327         // Are there toolbars in the super class?
328         sal_uInt16 nBaseCount = pGenoType->GetObjectBarCount();
329         if ( nNo < nBaseCount )
330             // The Super class comes first
331             return pGenoType->GetObjectBarFlags( nNo );
332         else
333             nNo = nNo - nBaseCount;
334     }
335 
336     assert( nNo<pImplData->aObjectBars.size() );
337 
338     return pImplData->aObjectBars[nNo]->nFlags;
339 }
340 
GetObjectBarCount() const341 sal_uInt16 SfxInterface::GetObjectBarCount() const
342 {
343     if (pGenoType && pGenoType->UseAsSuperClass())
344         return pImplData->aObjectBars.size() + pGenoType->GetObjectBarCount();
345     else
346         return pImplData->aObjectBars.size();
347 }
348 
RegisterChildWindow(sal_uInt16 nId,bool bContext)349 void SfxInterface::RegisterChildWindow(sal_uInt16 nId, bool bContext)
350 {
351     RegisterChildWindow(nId, bContext, SfxShellFeature::NONE);
352 }
353 
RegisterChildWindow(sal_uInt16 nId,bool bContext,SfxShellFeature nFeature)354 void SfxInterface::RegisterChildWindow(sal_uInt16 nId, bool bContext, SfxShellFeature nFeature)
355 {
356     SfxObjectUI_Impl* pUI = new SfxObjectUI_Impl(0, SfxVisibilityFlags::Invisible, nId, nFeature);
357     pUI->bContext = bContext;
358     pImplData->aChildWindows.emplace_back(pUI);
359 }
360 
RegisterStatusBar(StatusBarId eId)361 void SfxInterface::RegisterStatusBar(StatusBarId eId)
362 {
363     pImplData->eStatBarResId = eId;
364 }
365 
GetChildWindowId(sal_uInt16 nNo) const366 sal_uInt32 SfxInterface::GetChildWindowId (sal_uInt16 nNo) const
367 {
368     if ( pGenoType )
369     {
370         // Are there ChildWindows in the superclass?
371         sal_uInt16 nBaseCount = pGenoType->GetChildWindowCount();
372         if ( nNo < nBaseCount )
373             // The Super class comes first
374             return pGenoType->GetChildWindowId( nNo );
375         else
376             nNo = nNo - nBaseCount;
377     }
378 
379     assert( nNo<pImplData->aChildWindows.size() );
380 
381     sal_uInt32 nRet = pImplData->aChildWindows[nNo]->nObjId;
382     if ( pImplData->aChildWindows[nNo]->bContext )
383         nRet += sal_uInt16( nClassId ) << 16;
384     return nRet;
385 }
386 
GetChildWindowFeature(sal_uInt16 nNo) const387 SfxShellFeature SfxInterface::GetChildWindowFeature (sal_uInt16 nNo) const
388 {
389     if ( pGenoType )
390     {
391         // Are there ChildWindows in the superclass?
392         sal_uInt16 nBaseCount = pGenoType->GetChildWindowCount();
393         if ( nNo < nBaseCount )
394             // The Super class comes first
395             return pGenoType->GetChildWindowFeature( nNo );
396         else
397             nNo = nNo - nBaseCount;
398     }
399 
400     assert( nNo<pImplData->aChildWindows.size() );
401 
402     return pImplData->aChildWindows[nNo]->nFeature;
403 }
404 
405 
GetChildWindowCount() const406 sal_uInt16 SfxInterface::GetChildWindowCount() const
407 {
408     if (pGenoType)
409         return pImplData->aChildWindows.size() + pGenoType->GetChildWindowCount();
410     else
411         return pImplData->aChildWindows.size();
412 }
413 
GetPopupMenuName() const414 const OUString& SfxInterface::GetPopupMenuName() const
415 {
416     return pImplData->aPopupName;
417 }
418 
GetStatusBarId() const419 StatusBarId SfxInterface::GetStatusBarId() const
420 {
421     if (pImplData->eStatBarResId == StatusBarId::None && pGenoType)
422         return pGenoType->GetStatusBarId();
423     else
424         return pImplData->eStatBarResId;
425 }
426 
GetObjectBarFeature(sal_uInt16 nNo) const427 SfxShellFeature SfxInterface::GetObjectBarFeature ( sal_uInt16 nNo ) const
428 {
429     bool bGenoType = (pGenoType != nullptr && pGenoType->UseAsSuperClass());
430     if ( bGenoType )
431     {
432         // Are there toolbars in the super class?
433         sal_uInt16 nBaseCount = pGenoType->GetObjectBarCount();
434         if ( nNo < nBaseCount )
435             // The Super class comes first
436             return pGenoType->GetObjectBarFeature( nNo );
437         else
438             nNo = nNo - nBaseCount;
439     }
440 
441     assert( nNo<pImplData->aObjectBars.size() );
442 
443     return pImplData->aObjectBars[nNo]->nFeature;
444 }
445 
IsObjectBarVisible(sal_uInt16 nNo) const446 bool SfxInterface::IsObjectBarVisible(sal_uInt16 nNo) const
447 {
448     bool bGenoType = (pGenoType != nullptr && pGenoType->UseAsSuperClass());
449     if ( bGenoType )
450     {
451         // Are there toolbars in the super class?
452         sal_uInt16 nBaseCount = pGenoType->GetObjectBarCount();
453         if ( nNo < nBaseCount )
454             // The Super class comes first
455             return pGenoType->IsObjectBarVisible( nNo );
456         else
457             nNo = nNo - nBaseCount;
458     }
459 
460     assert( nNo<pImplData->aObjectBars.size() );
461 
462     return true;
463 }
464 
465 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
466