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  : ::cppu::BaseMutex ()
32 {
33 }
34 
35 
37 {
38 }
39 
40 
41 void NumberedCollection::setOwner(const css::uno::Reference< css::uno::XInterface >& xOwner)
42 {
43  // SYNCHRONIZED ->
44  osl::MutexGuard aLock(m_aMutex);
45 
46  m_xOwner = xOwner;
47 
48  // <- SYNCHRONIZED
49 }
50 
51 
53 {
54  // SYNCHRONIZED ->
55  osl::MutexGuard aLock(m_aMutex);
56 
58 
59  // <- SYNCHRONIZED
60 }
61 
62 
63 ::sal_Int32 SAL_CALL NumberedCollection::leaseNumber(const css::uno::Reference< css::uno::XInterface >& xComponent)
64 {
65  // SYNCHRONIZED ->
66  osl::MutexGuard aLock(m_aMutex);
67 
68  if ( ! xComponent.is ())
69  throw css::lang::IllegalArgumentException(ERRMSG_INVALID_COMPONENT_PARAM, m_xOwner.get(), 1);
70 
71  sal_IntPtr pComponent = reinterpret_cast<sal_IntPtr>( xComponent.get() );
72  TNumberedItemHash::const_iterator pIt = m_lComponents.find (pComponent);
73 
74  // a) component already exists - return its number directly
75  if (pIt != m_lComponents.end())
76  return pIt->second.nNumber;
77 
78  // b) component must be added new to this container
79 
80  // b1) collection is full - no further components possible
81  // -> return INVALID_NUMBER
82  ::sal_Int32 nFreeNumber = impl_searchFreeNumber();
83  if (nFreeNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
84  return css::frame::UntitledNumbersConst::INVALID_NUMBER;
85 
86  // b2) add component to collection and return its number
87  TNumberedItem aItem;
88  aItem.xItem = css::uno::WeakReference< css::uno::XInterface >(xComponent);
89  aItem.nNumber = nFreeNumber;
90  m_lComponents[pComponent] = aItem;
91 
92  return nFreeNumber;
93 
94  // <- SYNCHRONIZED
95 }
96 
97 
98 void SAL_CALL NumberedCollection::releaseNumber(::sal_Int32 nNumber)
99 {
100  // SYNCHRONIZED ->
101  osl::MutexGuard aLock(m_aMutex);
102 
103  if (nNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
104  throw css::lang::IllegalArgumentException ("Special valkud INVALID_NUMBER not allowed as input parameter.", m_xOwner.get(), 1);
105 
106  TDeadItemList lDeadItems;
107  TNumberedItemHash::iterator pComponent;
108 
109  for ( pComponent = m_lComponents.begin ();
110  pComponent != m_lComponents.end ();
111  ++pComponent )
112  {
113  const TNumberedItem& rItem = pComponent->second;
114  const css::uno::Reference< css::uno::XInterface > xItem = rItem.xItem.get();
115 
116  if ( ! xItem.is ())
117  {
118  lDeadItems.push_back(pComponent->first);
119  continue;
120  }
121 
122  if (rItem.nNumber == nNumber)
123  {
124  m_lComponents.erase (pComponent);
125  break;
126  }
127  }
128 
130 
131  // <- SYNCHRONIZED
132 }
133 
134 
135 void SAL_CALL NumberedCollection::releaseNumberForComponent(const css::uno::Reference< css::uno::XInterface >& xComponent)
136 {
137  // SYNCHRONIZED ->
138  osl::MutexGuard aLock(m_aMutex);
139 
140  if ( ! xComponent.is ())
141  throw css::lang::IllegalArgumentException(ERRMSG_INVALID_COMPONENT_PARAM, m_xOwner.get(), 1);
142 
143  sal_IntPtr pComponent = reinterpret_cast<sal_IntPtr>( xComponent.get() );
144  TNumberedItemHash::iterator pIt = m_lComponents.find (pComponent);
145 
146  // a) component exists and will be removed
147  if (pIt != m_lComponents.end())
148  m_lComponents.erase(pIt);
149 
150  // else
151  // b) component does not exists - nothing todo here (ignore request!)
152 
153  // <- SYNCHRONIZED
154 }
155 
156 
158 {
159  // SYNCHRONIZED ->
160  osl::MutexGuard aLock(m_aMutex);
161 
162  return m_sUntitledPrefix;
163 
164  // <- SYNCHRONIZED
165 }
166 
167 
181 {
182  // create ordered list of all possible numbers.
183  std::vector< ::sal_Int32 > lPossibleNumbers;
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  // SYNCHRONIZED ->
195  {
196  osl::MutexGuard aLock(m_aMutex);
197  TDeadItemList lDeadItems;
198 
199  for (const auto& [rComponent, rItem] : m_lComponents)
200  {
201  const css::uno::Reference< css::uno::XInterface > xItem = rItem.xItem.get();
202 
203  if ( ! xItem.is ())
204  {
205  lDeadItems.push_back(rComponent);
206  continue;
207  }
208 
209  std::vector< ::sal_Int32 >::iterator pPossible = std::find(lPossibleNumbers.begin (), lPossibleNumbers.end (), rItem.nNumber);
210  if (pPossible != lPossibleNumbers.end ())
211  lPossibleNumbers.erase (pPossible);
212  }
213 
214  impl_cleanUpDeadItems(m_lComponents, lDeadItems);
215 
216  // a) non free numbers ... return INVALID_NUMBER
217  if (lPossibleNumbers.empty())
218  return css::frame::UntitledNumbersConst::INVALID_NUMBER;
219 
220  // b) return first free number
221  return *(lPossibleNumbers.begin ());
222  }
223  // <- SYNCHRONIZED
224 }
225 
227  const TDeadItemList& lDeadItems)
228 {
229  for (const sal_IntPtr& rDeadItem : lDeadItems)
230  {
231  lItems.erase(rDeadItem);
232  }
233 }
234 
235 } // namespace comphelper
236 
237 /* 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.
mutable::osl::Mutex m_aMutex
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