xref: /trunk/main/comphelper/source/misc/numberedcollection.cxx (revision 9c15e1abd703a7953928d7a80655ae1a76a41f6d)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_comphelper.hxx"
26 
27 #include <comphelper/numberedcollection.hxx>
28 #include <algorithm>
29 
30 //_______________________________________________
31 // includes
32 
33 #include <com/sun/star/frame/UntitledNumbersConst.hpp>
34 
35 //_______________________________________________
36 // namespace
37 
38 namespace comphelper{
39 
40 namespace css = ::com::sun::star;
41 
42 //_______________________________________________
43 // definitions
44 
45 static const ::rtl::OUString ERRMSG_INVALID_COMPONENT_PARAM = ::rtl::OUString::createFromAscii("NULL as component reference not allowed.");
46 static const ::rtl::OUString ERRMSG_INVALID_NUMBER_PARAM    = ::rtl::OUString::createFromAscii("Special valkud INVALID_NUMBER not allowed as input parameter.");
47 
48 //-----------------------------------------------
49 NumberedCollection::NumberedCollection()
50     : ::cppu::BaseMutex ()
51     , m_sUntitledPrefix ()
52     , m_lComponents     ()
53     , m_xOwner          ()
54 {
55 }
56 
57 //-----------------------------------------------
58 NumberedCollection::~NumberedCollection()
59 {
60 }
61 
62 //-----------------------------------------------
63 void NumberedCollection::setOwner(const css::uno::Reference< css::uno::XInterface >& xOwner)
64 {
65     // SYNCHRONIZED ->
66     ::osl::ResettableMutexGuard aLock(m_aMutex);
67 
68         m_xOwner = xOwner;
69 
70     // <- SYNCHRONIZED
71 }
72 
73 //-----------------------------------------------
74 void NumberedCollection::setUntitledPrefix(const ::rtl::OUString& sPrefix)
75 {
76     // SYNCHRONIZED ->
77     ::osl::ResettableMutexGuard aLock(m_aMutex);
78 
79         m_sUntitledPrefix = sPrefix;
80 
81     // <- SYNCHRONIZED
82 }
83 
84 //-----------------------------------------------
85 ::sal_Int32 SAL_CALL NumberedCollection::leaseNumber(const css::uno::Reference< css::uno::XInterface >& xComponent)
86 {
87     // SYNCHRONIZED ->
88     ::osl::ResettableMutexGuard aLock(m_aMutex);
89 
90         if ( ! xComponent.is ())
91             throw css::lang::IllegalArgumentException (ERRMSG_INVALID_COMPONENT_PARAM, m_xOwner.get(), 1);
92 
93         long                              pComponent = (long) xComponent.get ();
94         TNumberedItemHash::const_iterator pIt        = m_lComponents.find (pComponent);
95 
96         // a) component already exists - return it's number directly
97         if (pIt != m_lComponents.end())
98             return pIt->second.nNumber;
99 
100         // b) component must be added new to this container
101 
102         // b1) collection is full - no further components possible
103         //     -> return INVALID_NUMBER
104         ::sal_Int32 nFreeNumber = impl_searchFreeNumber();
105         if (nFreeNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
106             return css::frame::UntitledNumbersConst::INVALID_NUMBER;
107 
108         // b2) add component to collection and return its number
109         TNumberedItem aItem;
110         aItem.xItem   = css::uno::WeakReference< css::uno::XInterface >(xComponent);
111         aItem.nNumber = nFreeNumber;
112         m_lComponents[pComponent] = aItem;
113 
114         return nFreeNumber;
115 
116     // <- SYNCHRONIZED
117 }
118 
119 //-----------------------------------------------
120 void SAL_CALL NumberedCollection::releaseNumber(::sal_Int32 nNumber)
121 {
122     // SYNCHRONIZED ->
123     ::osl::ResettableMutexGuard aLock(m_aMutex);
124 
125         if (nNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
126             throw css::lang::IllegalArgumentException (ERRMSG_INVALID_NUMBER_PARAM, m_xOwner.get(), 1);
127 
128         TDeadItemList               lDeadItems;
129         TNumberedItemHash::iterator pComponent;
130 
131         for (  pComponent  = m_lComponents.begin ();
132                pComponent != m_lComponents.end   ();
133              ++pComponent                          )
134         {
135             const TNumberedItem&                              rItem = pComponent->second;
136             const css::uno::Reference< css::uno::XInterface > xItem = rItem.xItem.get();
137 
138             if ( ! xItem.is ())
139             {
140                 lDeadItems.push_back(pComponent->first);
141                 continue;
142             }
143 
144             if (rItem.nNumber == nNumber)
145             {
146                 m_lComponents.erase (pComponent);
147                 break;
148             }
149         }
150 
151         impl_cleanUpDeadItems(m_lComponents, lDeadItems);
152 
153     // <- SYNCHRONIZED
154 }
155 
156 //-----------------------------------------------
157 void SAL_CALL NumberedCollection::releaseNumberForComponent(const css::uno::Reference< css::uno::XInterface >& xComponent)
158 {
159     // SYNCHRONIZED ->
160     ::osl::ResettableMutexGuard aLock(m_aMutex);
161 
162         if ( ! xComponent.is ())
163             throw css::lang::IllegalArgumentException (ERRMSG_INVALID_COMPONENT_PARAM, m_xOwner.get(), 1);
164 
165         long                        pComponent = (long) xComponent.get ();
166         TNumberedItemHash::iterator pIt        = m_lComponents.find (pComponent);
167 
168         // a) component exists and will be removed
169         if (pIt != m_lComponents.end())
170             m_lComponents.erase(pIt);
171 
172         // else
173         // b) component does not exists - nothing todo here (ignore request!)
174 
175     // <- SYNCHRONIZED
176 }
177 
178 //-----------------------------------------------
179 ::rtl::OUString SAL_CALL NumberedCollection::getUntitledPrefix()
180 {
181     // SYNCHRONIZED ->
182     ::osl::ResettableMutexGuard aLock(m_aMutex);
183 
184         return m_sUntitledPrefix;
185 
186     // <- SYNCHRONIZED
187 }
188 
189 //-----------------------------------------------
190 /** create an ordered list of all possible numbers ...
191     e.g. {1,2,3,...,N} Max size of these list will be
192     current size of component list + 1 .
193 
194     "+1" ... because in case all numbers in range 1..n
195     are in use we need a new number n+1 :-)
196 
197     Every item which is already used as unique number
198     will be removed. At the end a list of e.g. {3,6,...,M}
199     exists where the first item represent the lowest free
200     number (in this example 3).
201  */
202 ::sal_Int32 NumberedCollection::impl_searchFreeNumber ()
203 {
204     // create ordered list of all possible numbers.
205     ::std::vector< ::sal_Int32 > lPossibleNumbers;
206     ::sal_Int32                  c = (::sal_Int32)m_lComponents.size ();
207     ::sal_Int32                  i = 1;
208 
209     // c can't be less than 0 ... otherwise hash.size() has an error :-)
210     // But we need at least n+1 numbers here.
211     c += 1;
212 
213     for (i=1; i<=c; ++i)
214         lPossibleNumbers.push_back (i);
215 
216     // SYNCHRONIZED ->
217     ::osl::ResettableMutexGuard aLock(m_aMutex);
218 
219         TDeadItemList                     lDeadItems;
220         TNumberedItemHash::const_iterator pComponent;
221 
222         for (  pComponent  = m_lComponents.begin ();
223                pComponent != m_lComponents.end   ();
224              ++pComponent                          )
225         {
226             const TNumberedItem&                              rItem = pComponent->second;
227             const css::uno::Reference< css::uno::XInterface > xItem = rItem.xItem.get();
228 
229             if ( ! xItem.is ())
230             {
231                 lDeadItems.push_back(pComponent->first);
232                 continue;
233             }
234 
235             ::std::vector< ::sal_Int32 >::iterator pPossible = ::std::find(lPossibleNumbers.begin (), lPossibleNumbers.end (), rItem.nNumber);
236             if (pPossible != lPossibleNumbers.end ())
237                 lPossibleNumbers.erase (pPossible);
238         }
239 
240         impl_cleanUpDeadItems(m_lComponents, lDeadItems);
241 
242         // a) non free numbers ... return INVALID_NUMBER
243         if (lPossibleNumbers.size () < 1)
244             return css::frame::UntitledNumbersConst::INVALID_NUMBER;
245 
246         // b) return first free number
247         return *(lPossibleNumbers.begin ());
248 
249     // <- SYNCHRONIZED
250 }
251 
252 void NumberedCollection::impl_cleanUpDeadItems (      TNumberedItemHash& lItems    ,
253                                                 const TDeadItemList&     lDeadItems)
254 {
255     TDeadItemList::const_iterator pIt;
256 
257     for (  pIt  = lDeadItems.begin ();
258            pIt != lDeadItems.end   ();
259          ++pIt                       )
260     {
261         const long& rDeadItem = *pIt;
262         lItems.erase(rDeadItem);
263     }
264 }
265 
266 } // namespace comphelper
267