LibreOffice Module comphelper (master)  1
numberedcollection.cxx
Go to the documentation of this file.
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 <algorithm>
22 #include <com/sun/star/frame/UntitledNumbersConst.hpp>
23 #include <com/sun/star/lang/IllegalArgumentException.hpp>
24 
25 namespace comphelper{
26 
27 constexpr OUStringLiteral ERRMSG_INVALID_COMPONENT_PARAM = u"NULL as component reference not allowed.";
28 
29 
31 {
32 }
33 
34 
36 {
37 }
38 
39 
40 void NumberedCollection::setOwner(const css::uno::Reference< css::uno::XInterface >& xOwner)
41 {
42  // SYNCHRONIZED ->
43  std::scoped_lock aLock(m_aMutex);
44 
45  m_xOwner = xOwner;
46 
47  // <- SYNCHRONIZED
48 }
49 
50 
52 {
53  // SYNCHRONIZED ->
54  std::scoped_lock aLock(m_aMutex);
55 
57 
58  // <- SYNCHRONIZED
59 }
60 
61 
62 ::sal_Int32 SAL_CALL NumberedCollection::leaseNumber(const css::uno::Reference< css::uno::XInterface >& xComponent)
63 {
64  // SYNCHRONIZED ->
65  std::scoped_lock aLock(m_aMutex);
66 
67  if ( ! xComponent.is ())
68  throw css::lang::IllegalArgumentException(ERRMSG_INVALID_COMPONENT_PARAM, m_xOwner.get(), 1);
69 
70  sal_IntPtr pComponent = reinterpret_cast<sal_IntPtr>( xComponent.get() );
71  TNumberedItemHash::const_iterator pIt = m_lComponents.find (pComponent);
72 
73  // a) component already exists - return its number directly
74  if (pIt != m_lComponents.end())
75  return pIt->second.nNumber;
76 
77  // b) component must be added new to this container
78 
79  // b1) collection is full - no further components possible
80  // -> return INVALID_NUMBER
81  ::sal_Int32 nFreeNumber = impl_searchFreeNumber();
82  if (nFreeNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
83  return css::frame::UntitledNumbersConst::INVALID_NUMBER;
84 
85  // b2) add component to collection and return its number
86  TNumberedItem aItem;
87  aItem.xItem = css::uno::WeakReference< css::uno::XInterface >(xComponent);
88  aItem.nNumber = nFreeNumber;
89  m_lComponents[pComponent] = aItem;
90 
91  return nFreeNumber;
92 
93  // <- SYNCHRONIZED
94 }
95 
96 
97 void SAL_CALL NumberedCollection::releaseNumber(::sal_Int32 nNumber)
98 {
99  // SYNCHRONIZED ->
100  std::scoped_lock aLock(m_aMutex);
101 
102  if (nNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
103  throw css::lang::IllegalArgumentException ("Special valkud INVALID_NUMBER not allowed as input parameter.", m_xOwner.get(), 1);
104 
105  TDeadItemList lDeadItems;
106  TNumberedItemHash::iterator pComponent;
107 
108  for ( pComponent = m_lComponents.begin ();
109  pComponent != m_lComponents.end ();
110  ++pComponent )
111  {
112  const TNumberedItem& rItem = pComponent->second;
113  const css::uno::Reference< css::uno::XInterface > xItem = rItem.xItem.get();
114 
115  if ( ! xItem.is ())
116  {
117  lDeadItems.push_back(pComponent->first);
118  continue;
119  }
120 
121  if (rItem.nNumber == nNumber)
122  {
123  m_lComponents.erase (pComponent);
124  break;
125  }
126  }
127 
129 
130  // <- SYNCHRONIZED
131 }
132 
133 
134 void SAL_CALL NumberedCollection::releaseNumberForComponent(const css::uno::Reference< css::uno::XInterface >& xComponent)
135 {
136  // SYNCHRONIZED ->
137  std::scoped_lock aLock(m_aMutex);
138 
139  if ( ! xComponent.is ())
140  throw css::lang::IllegalArgumentException(ERRMSG_INVALID_COMPONENT_PARAM, m_xOwner.get(), 1);
141 
142  sal_IntPtr pComponent = reinterpret_cast<sal_IntPtr>( xComponent.get() );
143  TNumberedItemHash::iterator pIt = m_lComponents.find (pComponent);
144 
145  // a) component exists and will be removed
146  if (pIt != m_lComponents.end())
147  m_lComponents.erase(pIt);
148 
149  // else
150  // b) component does not exists - nothing todo here (ignore request!)
151 
152  // <- SYNCHRONIZED
153 }
154 
155 
157 {
158  // SYNCHRONIZED ->
159  std::scoped_lock aLock(m_aMutex);
160 
161  return m_sUntitledPrefix;
162 
163  // <- SYNCHRONIZED
164 }
165 
166 
180 {
181  // create ordered list of all possible numbers.
182  std::vector< ::sal_Int32 > lPossibleNumbers;
183  lPossibleNumbers.reserve(m_lComponents.size() + 1);
184  ::sal_Int32 c = static_cast<::sal_Int32>(m_lComponents.size ());
185  ::sal_Int32 i = 1;
186 
187  // c can't be less than 0 ... otherwise hash.size() has an error :-)
188  // But we need at least n+1 numbers here.
189  c += 1;
190 
191  for (i=1; i<=c; ++i)
192  lPossibleNumbers.push_back (i);
193 
194  for (const auto& rPair : m_lComponents)
195  {
196  std::vector< ::sal_Int32 >::iterator pPossible = std::find(lPossibleNumbers.begin (), lPossibleNumbers.end (), rPair.second.nNumber);
197  if (pPossible != lPossibleNumbers.end ())
198  lPossibleNumbers.erase (pPossible);
199  }
200 
201  // a) non free numbers ... return INVALID_NUMBER
202  if (lPossibleNumbers.empty())
203  return css::frame::UntitledNumbersConst::INVALID_NUMBER;
204 
205  // b) return first free number
206  return *(lPossibleNumbers.begin ());
207 }
208 
210  const TDeadItemList& lDeadItems)
211 {
212  for (const sal_IntPtr& rDeadItem : lDeadItems)
213  {
214  lItems.erase(rDeadItem);
215  }
216 }
217 
218 } // namespace comphelper
219 
220 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual ~NumberedCollection() override
free all internally used resources.
::sal_Int32 impl_searchFreeNumber()
tries to find a unique number not already used within this collection.
std::unordered_map< sal_IntPtr, TNumberedItem > TNumberedItemHash
virtual void SAL_CALL releaseNumberForComponent(const css::uno::Reference< css::uno::XInterface > &xComponent) override
css::uno::WeakReference< css::uno::XInterface > m_xOwner
used as source of broadcasted messages or exceptions (can be null !)
OUString sPrefix
int i
virtual OUString SAL_CALL getUntitledPrefix() override
css::uno::WeakReference< css::uno::XInterface > xItem
constexpr OUStringLiteral ERRMSG_INVALID_COMPONENT_PARAM
Mutex aLock
float u
virtual ::sal_Int32 SAL_CALL leaseNumber(const css::uno::Reference< css::uno::XInterface > &xComponent) override
static void impl_cleanUpDeadItems(TNumberedItemHash &lItems, const TDeadItemList &lDeadItems)
static PropertyMapEntry const * find(const rtl::Reference< PropertySetInfo > &mxInfo, const OUString &aName) noexcept
OUString m_sUntitledPrefix
localized string to be used for untitled components
TNumberedItemHash m_lComponents
cache of all "leased numbers" and its bound components
::std::vector< sal_IntPtr > TDeadItemList
void setOwner(const css::uno::Reference< css::uno::XInterface > &xOwner)
set an outside component which uses this container and must be set as source of all broadcasted messa...
NumberedCollection()
lightweight constructor.
void setUntitledPrefix(const OUString &sPrefix)
set the localized prefix to be used for untitled components.
virtual void SAL_CALL releaseNumber(::sal_Int32 nNumber) override