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 static const char ERRMSG_INVALID_COMPONENT_PARAM[] = "NULL as component reference not allowed.";
28 
29 
31  : ::cppu::BaseMutex ()
32  , m_sUntitledPrefix ()
33  , m_lComponents ()
34  , m_xOwner ()
35 {
36 }
37 
38 
40 {
41 }
42 
43 
44 void NumberedCollection::setOwner(const css::uno::Reference< css::uno::XInterface >& xOwner)
45 {
46  // SYNCHRONIZED ->
47  osl::MutexGuard aLock(m_aMutex);
48 
49  m_xOwner = xOwner;
50 
51  // <- SYNCHRONIZED
52 }
53 
54 
56 {
57  // SYNCHRONIZED ->
58  osl::MutexGuard aLock(m_aMutex);
59 
61 
62  // <- SYNCHRONIZED
63 }
64 
65 
66 ::sal_Int32 SAL_CALL NumberedCollection::leaseNumber(const css::uno::Reference< css::uno::XInterface >& xComponent)
67 {
68  // SYNCHRONIZED ->
69  osl::MutexGuard aLock(m_aMutex);
70 
71  if ( ! xComponent.is ())
72  throw css::lang::IllegalArgumentException(ERRMSG_INVALID_COMPONENT_PARAM, m_xOwner.get(), 1);
73 
74  sal_IntPtr pComponent = reinterpret_cast<sal_IntPtr>( xComponent.get() );
75  TNumberedItemHash::const_iterator pIt = m_lComponents.find (pComponent);
76 
77  // a) component already exists - return its number directly
78  if (pIt != m_lComponents.end())
79  return pIt->second.nNumber;
80 
81  // b) component must be added new to this container
82 
83  // b1) collection is full - no further components possible
84  // -> return INVALID_NUMBER
85  ::sal_Int32 nFreeNumber = impl_searchFreeNumber();
86  if (nFreeNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
87  return css::frame::UntitledNumbersConst::INVALID_NUMBER;
88 
89  // b2) add component to collection and return its number
90  TNumberedItem aItem;
91  aItem.xItem = css::uno::WeakReference< css::uno::XInterface >(xComponent);
92  aItem.nNumber = nFreeNumber;
93  m_lComponents[pComponent] = aItem;
94 
95  return nFreeNumber;
96 
97  // <- SYNCHRONIZED
98 }
99 
100 
101 void SAL_CALL NumberedCollection::releaseNumber(::sal_Int32 nNumber)
102 {
103  // SYNCHRONIZED ->
104  osl::MutexGuard aLock(m_aMutex);
105 
106  if (nNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
107  throw css::lang::IllegalArgumentException ("Special valkud INVALID_NUMBER not allowed as input parameter.", m_xOwner.get(), 1);
108 
109  TDeadItemList lDeadItems;
110  TNumberedItemHash::iterator pComponent;
111 
112  for ( pComponent = m_lComponents.begin ();
113  pComponent != m_lComponents.end ();
114  ++pComponent )
115  {
116  const TNumberedItem& rItem = pComponent->second;
117  const css::uno::Reference< css::uno::XInterface > xItem = rItem.xItem.get();
118 
119  if ( ! xItem.is ())
120  {
121  lDeadItems.push_back(pComponent->first);
122  continue;
123  }
124 
125  if (rItem.nNumber == nNumber)
126  {
127  m_lComponents.erase (pComponent);
128  break;
129  }
130  }
131 
133 
134  // <- SYNCHRONIZED
135 }
136 
137 
138 void SAL_CALL NumberedCollection::releaseNumberForComponent(const css::uno::Reference< css::uno::XInterface >& xComponent)
139 {
140  // SYNCHRONIZED ->
141  osl::MutexGuard aLock(m_aMutex);
142 
143  if ( ! xComponent.is ())
144  throw css::lang::IllegalArgumentException(ERRMSG_INVALID_COMPONENT_PARAM, m_xOwner.get(), 1);
145 
146  sal_IntPtr pComponent = reinterpret_cast<sal_IntPtr>( xComponent.get() );
147  TNumberedItemHash::iterator pIt = m_lComponents.find (pComponent);
148 
149  // a) component exists and will be removed
150  if (pIt != m_lComponents.end())
151  m_lComponents.erase(pIt);
152 
153  // else
154  // b) component does not exists - nothing todo here (ignore request!)
155 
156  // <- SYNCHRONIZED
157 }
158 
159 
161 {
162  // SYNCHRONIZED ->
163  osl::MutexGuard aLock(m_aMutex);
164 
165  return m_sUntitledPrefix;
166 
167  // <- SYNCHRONIZED
168 }
169 
170 
184 {
185  // create ordered list of all possible numbers.
186  std::vector< ::sal_Int32 > lPossibleNumbers;
187  ::sal_Int32 c = static_cast<::sal_Int32>(m_lComponents.size ());
188  ::sal_Int32 i = 1;
189 
190  // c can't be less than 0 ... otherwise hash.size() has an error :-)
191  // But we need at least n+1 numbers here.
192  c += 1;
193 
194  for (i=1; i<=c; ++i)
195  lPossibleNumbers.push_back (i);
196 
197  // SYNCHRONIZED ->
198  {
199  osl::MutexGuard aLock(m_aMutex);
200  TDeadItemList lDeadItems;
201 
202  for (const auto& [rComponent, rItem] : m_lComponents)
203  {
204  const css::uno::Reference< css::uno::XInterface > xItem = rItem.xItem.get();
205 
206  if ( ! xItem.is ())
207  {
208  lDeadItems.push_back(rComponent);
209  continue;
210  }
211 
212  std::vector< ::sal_Int32 >::iterator pPossible = std::find(lPossibleNumbers.begin (), lPossibleNumbers.end (), rItem.nNumber);
213  if (pPossible != lPossibleNumbers.end ())
214  lPossibleNumbers.erase (pPossible);
215  }
216 
217  impl_cleanUpDeadItems(m_lComponents, lDeadItems);
218 
219  // a) non free numbers ... return INVALID_NUMBER
220  if (lPossibleNumbers.empty())
221  return css::frame::UntitledNumbersConst::INVALID_NUMBER;
222 
223  // b) return first free number
224  return *(lPossibleNumbers.begin ());
225  }
226  // <- SYNCHRONIZED
227 }
228 
230  const TDeadItemList& lDeadItems)
231 {
232  for (const long& rDeadItem : lDeadItems)
233  {
234  lItems.erase(rDeadItem);
235  }
236 }
237 
238 } // namespace comphelper
239 
240 /* 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
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
virtual OUString SAL_CALL getUntitledPrefix() override
css::uno::WeakReference< css::uno::XInterface > xItem
int i
virtual ::sal_Int32 SAL_CALL leaseNumber(const css::uno::Reference< css::uno::XInterface > &xComponent) override
static void impl_cleanUpDeadItems(TNumberedItemHash &lItems, const TDeadItemList &lDeadItems)
OUString m_sUntitledPrefix
localized string to be used for untitled components
TNumberedItemHash m_lComponents
cache of all "leased numbers" and its bound components
std::unordered_map< long, TNumberedItem > TNumberedItemHash
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.
::std::vector< long > TDeadItemList
void setUntitledPrefix(const OUString &sPrefix)
set the localized prefix to be used for untitled components.
static const char ERRMSG_INVALID_COMPONENT_PARAM[]
virtual void SAL_CALL releaseNumber(::sal_Int32 nNumber) override