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_forms.hxx"
26 #include "entrylisthelper.hxx"
27 #include "FormComponent.hxx"
28 
29 #include <osl/diagnose.h>
30 #include <comphelper/sequence.hxx>
31 #include <comphelper/property.hxx>
32 #include <algorithm>
33 
34 //.........................................................................
35 namespace frm
36 {
37 //.........................................................................
38 
39     using namespace ::com::sun::star::uno;
40     using namespace ::com::sun::star::lang;
41     using namespace ::com::sun::star::util;
42     using namespace ::com::sun::star::form::binding;
43 
44     //=====================================================================
45     //= OEntryListHelper
46     //=====================================================================
47     //---------------------------------------------------------------------
OEntryListHelper(OControlModel & _rControlModel)48     OEntryListHelper::OEntryListHelper( OControlModel& _rControlModel )
49         :m_rControlModel( _rControlModel )
50         ,m_aRefreshListeners( _rControlModel.getInstanceMutex() )
51     {
52     }
53 
54     //---------------------------------------------------------------------
OEntryListHelper(const OEntryListHelper & _rSource,OControlModel & _rControlModel)55     OEntryListHelper::OEntryListHelper( const OEntryListHelper& _rSource, OControlModel& _rControlModel )
56         :m_rControlModel( _rControlModel )
57         ,m_xListSource ( _rSource.m_xListSource  )
58         ,m_aStringItems( _rSource.m_aStringItems )
59         ,m_aRefreshListeners( _rControlModel.getInstanceMutex() )
60     {
61     }
62 
63     //---------------------------------------------------------------------
~OEntryListHelper()64     OEntryListHelper::~OEntryListHelper( )
65     {
66     }
67 
68     //---------------------------------------------------------------------
setListEntrySource(const Reference<XListEntrySource> & _rxSource)69     void SAL_CALL OEntryListHelper::setListEntrySource( const Reference< XListEntrySource >& _rxSource ) throw (RuntimeException)
70     {
71         ControlModelLock aLock( m_rControlModel );
72 
73         // disconnect from the current external list source
74         disconnectExternalListSource();
75 
76         // and connect to the new one
77         if ( _rxSource.is() )
78             connectExternalListSource( _rxSource, aLock );
79     }
80 
81     //---------------------------------------------------------------------
getListEntrySource()82     Reference< XListEntrySource > SAL_CALL OEntryListHelper::getListEntrySource(  ) throw (RuntimeException)
83     {
84         return m_xListSource;
85     }
86 
87 
88     //---------------------------------------------------------------------
entryChanged(const ListEntryEvent & _rEvent)89     void SAL_CALL OEntryListHelper::entryChanged( const ListEntryEvent& _rEvent ) throw (RuntimeException)
90     {
91         ControlModelLock aLock( m_rControlModel );
92 
93         OSL_ENSURE( _rEvent.Source == m_xListSource,
94             "OEntryListHelper::entryChanged: where did this come from?" );
95         OSL_ENSURE( ( _rEvent.Position >= 0 ) && ( _rEvent.Position < m_aStringItems.getLength() ),
96             "OEntryListHelper::entryChanged: invalid index!" );
97         OSL_ENSURE( _rEvent.Entries.getLength() == 1,
98             "OEntryListHelper::entryChanged: invalid string list!" );
99 
100         if  (   ( _rEvent.Position >= 0 )
101             &&  ( _rEvent.Position < m_aStringItems.getLength() )
102             &&  ( _rEvent.Entries.getLength() > 0 )
103             )
104         {
105             m_aStringItems[ _rEvent.Position ] = _rEvent.Entries[ 0 ];
106             stringItemListChanged( aLock );
107         }
108     }
109 
110     //---------------------------------------------------------------------
entryRangeInserted(const ListEntryEvent & _rEvent)111     void SAL_CALL OEntryListHelper::entryRangeInserted( const ListEntryEvent& _rEvent ) throw (RuntimeException)
112     {
113         ControlModelLock aLock( m_rControlModel );
114 
115         OSL_ENSURE( _rEvent.Source == m_xListSource,
116             "OEntryListHelper::entryRangeInserted: where did this come from?" );
117         OSL_ENSURE( ( _rEvent.Position > 0 ) && ( _rEvent.Position < m_aStringItems.getLength() ) && ( _rEvent.Entries.getLength() > 0 ),
118             "OEntryListHelper::entryRangeRemoved: invalid count and/or position!" );
119 
120         if  (   ( _rEvent.Position > 0 )
121             &&  ( _rEvent.Position < m_aStringItems.getLength() )
122             &&  ( _rEvent.Entries.getLength() > 0 )
123             )
124         {
125             // the entries *before* the insertion pos
126             Sequence< ::rtl::OUString > aKeepEntries(
127                 m_aStringItems.getConstArray(),
128                 _rEvent.Position
129             );
130             // the entries *behind* the insertion pos
131             Sequence< ::rtl::OUString > aMovedEntries(
132                 m_aStringItems.getConstArray() + _rEvent.Position,
133                 m_aStringItems.getLength() - _rEvent.Position
134             );
135 
136             // concat all three parts
137             m_aStringItems = ::comphelper::concatSequences(
138                 aKeepEntries,
139                 _rEvent.Entries,
140                 aMovedEntries
141             );
142 
143             stringItemListChanged( aLock );
144         }
145     }
146 
147     //---------------------------------------------------------------------
entryRangeRemoved(const ListEntryEvent & _rEvent)148     void SAL_CALL OEntryListHelper::entryRangeRemoved( const ListEntryEvent& _rEvent ) throw (RuntimeException)
149     {
150         ControlModelLock aLock( m_rControlModel );
151 
152         OSL_ENSURE( _rEvent.Source == m_xListSource,
153             "OEntryListHelper::entryRangeRemoved: where did this come from?" );
154         OSL_ENSURE( ( _rEvent.Position > 0 ) && ( _rEvent.Count > 0 ) && ( _rEvent.Position + _rEvent.Count <= m_aStringItems.getLength() ),
155             "OEntryListHelper::entryRangeRemoved: invalid count and/or position!" );
156 
157         if  (   ( _rEvent.Position > 0 )
158             &&  ( _rEvent.Count > 0 )
159             &&  ( _rEvent.Position + _rEvent.Count <= m_aStringItems.getLength() )
160             )
161         {
162             // copy all items after the removed ones
163             ::std::copy(
164                 m_aStringItems.getConstArray() + _rEvent.Position + _rEvent.Count,
165                 m_aStringItems.getConstArray() + m_aStringItems.getLength(),
166                 m_aStringItems.getArray( ) + _rEvent.Position
167             );
168             // shrink the array
169             m_aStringItems.realloc( m_aStringItems.getLength() - _rEvent.Count );
170 
171             stringItemListChanged( aLock );
172         }
173     }
174 
175     //---------------------------------------------------------------------
allEntriesChanged(const EventObject & _rEvent)176     void SAL_CALL OEntryListHelper::allEntriesChanged( const EventObject& _rEvent ) throw (RuntimeException)
177     {
178         ControlModelLock aLock( m_rControlModel );
179 
180         OSL_ENSURE( _rEvent.Source == m_xListSource,
181             "OEntryListHelper::allEntriesChanged: where did this come from?" );
182 
183         Reference< XListEntrySource > xSource( _rEvent.Source, UNO_QUERY );
184         if ( _rEvent.Source == m_xListSource )
185         {
186             impl_lock_refreshList( aLock );
187         }
188     }
189 
190     // XRefreshable
191     //------------------------------------------------------------------------------
addRefreshListener(const Reference<XRefreshListener> & _rxListener)192     void SAL_CALL OEntryListHelper::addRefreshListener(const Reference<XRefreshListener>& _rxListener) throw(RuntimeException)
193     {
194         if ( _rxListener.is() )
195             m_aRefreshListeners.addInterface( _rxListener );
196     }
197 
198     //------------------------------------------------------------------------------
removeRefreshListener(const Reference<XRefreshListener> & _rxListener)199     void SAL_CALL OEntryListHelper::removeRefreshListener(const Reference<XRefreshListener>& _rxListener) throw(RuntimeException)
200     {
201         if ( _rxListener.is() )
202             m_aRefreshListeners.removeInterface( _rxListener );
203     }
204 
205     //------------------------------------------------------------------------------
refresh()206     void SAL_CALL OEntryListHelper::refresh() throw(RuntimeException)
207     {
208         {
209             ControlModelLock aLock( m_rControlModel );
210             impl_lock_refreshList( aLock );
211         }
212 
213         EventObject aEvt( static_cast< XRefreshable* >( this ) );
214         m_aRefreshListeners.notifyEach( &XRefreshListener::refreshed, aEvt );
215     }
216 
217     //---------------------------------------------------------------------
impl_lock_refreshList(ControlModelLock & _rInstanceLock)218     void OEntryListHelper::impl_lock_refreshList( ControlModelLock& _rInstanceLock )
219     {
220         if ( hasExternalListSource() )
221         {
222             m_aStringItems = m_xListSource->getAllListEntries( );
223             stringItemListChanged( _rInstanceLock );
224         }
225         else
226             refreshInternalEntryList();
227     }
228 
229     //---------------------------------------------------------------------
handleDisposing(const EventObject & _rEvent)230     bool OEntryListHelper::handleDisposing( const EventObject& _rEvent )
231     {
232         if ( m_xListSource .is() && ( _rEvent.Source == m_xListSource ) )
233         {
234             disconnectExternalListSource( );
235             return true;
236         }
237         return false;
238     }
239 
240     //---------------------------------------------------------------------
disposing()241     void OEntryListHelper::disposing( )
242     {
243         EventObject aEvt( static_cast< XRefreshable* >( this ) );
244         m_aRefreshListeners.disposeAndClear(aEvt);
245 
246         if ( hasExternalListSource( ) )
247             disconnectExternalListSource( );
248     }
249 
250     //---------------------------------------------------------------------
disconnectExternalListSource()251     void OEntryListHelper::disconnectExternalListSource( )
252     {
253         if ( m_xListSource.is() )
254             m_xListSource->removeListEntryListener( this );
255 
256         m_xListSource.clear();
257 
258         disconnectedExternalListSource();
259     }
260 
261     //---------------------------------------------------------------------
connectedExternalListSource()262     void OEntryListHelper::connectedExternalListSource( )
263     {
264         // nothing to do here
265     }
266 
267     //---------------------------------------------------------------------
disconnectedExternalListSource()268     void OEntryListHelper::disconnectedExternalListSource( )
269     {
270         // nothing to do here
271     }
272 
273     //---------------------------------------------------------------------
connectExternalListSource(const Reference<XListEntrySource> & _rxSource,ControlModelLock & _rInstanceLock)274     void OEntryListHelper::connectExternalListSource( const Reference< XListEntrySource >& _rxSource, ControlModelLock& _rInstanceLock )
275     {
276         OSL_ENSURE( !hasExternalListSource(), "OEntryListHelper::connectExternalListSource: only to be called if no external source is active!" );
277         OSL_ENSURE( _rxSource.is(), "OEntryListHelper::connectExternalListSource: invalid list source!" );
278 
279         // remember it
280         m_xListSource = _rxSource;
281 
282         // initially fill our item list
283         if ( m_xListSource.is() )
284         {
285             // be notified when the list changes ...
286             m_xListSource->addListEntryListener( this );
287 
288             m_aStringItems = m_xListSource->getAllListEntries( );
289             stringItemListChanged( _rInstanceLock );
290 
291             // let derivees react on the new list source
292             connectedExternalListSource();
293         }
294     }
295 
296     //---------------------------------------------------------------------
convertNewListSourceProperty(Any & _rConvertedValue,Any & _rOldValue,const Any & _rValue)297     sal_Bool OEntryListHelper::convertNewListSourceProperty( Any& _rConvertedValue,
298         Any& _rOldValue, const Any& _rValue ) SAL_THROW( ( IllegalArgumentException ) )
299     {
300         if ( hasExternalListSource() )
301             throw IllegalArgumentException( );
302             // TODO: error message
303 
304         return ::comphelper::tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, m_aStringItems );
305     }
306 
307     //---------------------------------------------------------------------
setNewStringItemList(const::com::sun::star::uno::Any & _rValue,ControlModelLock & _rInstanceLock)308     void OEntryListHelper::setNewStringItemList( const ::com::sun::star::uno::Any& _rValue, ControlModelLock& _rInstanceLock )
309     {
310         OSL_PRECOND( !hasExternalListSource(), "OEntryListHelper::setNewStringItemList: this should never have survived convertNewListSourceProperty!" );
311         OSL_VERIFY( _rValue >>= m_aStringItems );
312         stringItemListChanged( _rInstanceLock );
313     }
314 
315 //.........................................................................
316 }   // namespace frm
317 //.........................................................................
318