1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_forms.hxx"
30 #include "entrylisthelper.hxx"
31 #include "FormComponent.hxx"
32 
33 #include <osl/diagnose.h>
34 #include <comphelper/sequence.hxx>
35 #include <comphelper/property.hxx>
36 #include <algorithm>
37 
38 //.........................................................................
39 namespace frm
40 {
41 //.........................................................................
42 
43     using namespace ::com::sun::star::uno;
44     using namespace ::com::sun::star::lang;
45     using namespace ::com::sun::star::util;
46     using namespace ::com::sun::star::form::binding;
47 
48     //=====================================================================
49     //= OEntryListHelper
50     //=====================================================================
51     //---------------------------------------------------------------------
52     OEntryListHelper::OEntryListHelper( OControlModel& _rControlModel )
53         :m_rControlModel( _rControlModel )
54         ,m_aRefreshListeners( _rControlModel.getInstanceMutex() )
55     {
56     }
57 
58     //---------------------------------------------------------------------
59     OEntryListHelper::OEntryListHelper( const OEntryListHelper& _rSource, OControlModel& _rControlModel )
60         :m_rControlModel( _rControlModel )
61         ,m_xListSource ( _rSource.m_xListSource  )
62         ,m_aStringItems( _rSource.m_aStringItems )
63         ,m_aRefreshListeners( _rControlModel.getInstanceMutex() )
64     {
65     }
66 
67     //---------------------------------------------------------------------
68     OEntryListHelper::~OEntryListHelper( )
69     {
70     }
71 
72     //---------------------------------------------------------------------
73     void SAL_CALL OEntryListHelper::setListEntrySource( const Reference< XListEntrySource >& _rxSource ) throw (RuntimeException)
74     {
75         ControlModelLock aLock( m_rControlModel );
76 
77         // disconnect from the current external list source
78         disconnectExternalListSource();
79 
80         // and connect to the new one
81         if ( _rxSource.is() )
82             connectExternalListSource( _rxSource, aLock );
83     }
84 
85     //---------------------------------------------------------------------
86     Reference< XListEntrySource > SAL_CALL OEntryListHelper::getListEntrySource(  ) throw (RuntimeException)
87     {
88         return m_xListSource;
89     }
90 
91 
92     //---------------------------------------------------------------------
93     void SAL_CALL OEntryListHelper::entryChanged( const ListEntryEvent& _rEvent ) throw (RuntimeException)
94     {
95         ControlModelLock aLock( m_rControlModel );
96 
97         OSL_ENSURE( _rEvent.Source == m_xListSource,
98             "OEntryListHelper::entryChanged: where did this come from?" );
99         OSL_ENSURE( ( _rEvent.Position >= 0 ) && ( _rEvent.Position < m_aStringItems.getLength() ),
100             "OEntryListHelper::entryChanged: invalid index!" );
101         OSL_ENSURE( _rEvent.Entries.getLength() == 1,
102             "OEntryListHelper::entryChanged: invalid string list!" );
103 
104         if  (   ( _rEvent.Position >= 0 )
105             &&  ( _rEvent.Position < m_aStringItems.getLength() )
106             &&  ( _rEvent.Entries.getLength() > 0 )
107             )
108         {
109             m_aStringItems[ _rEvent.Position ] = _rEvent.Entries[ 0 ];
110             stringItemListChanged( aLock );
111         }
112     }
113 
114     //---------------------------------------------------------------------
115     void SAL_CALL OEntryListHelper::entryRangeInserted( const ListEntryEvent& _rEvent ) throw (RuntimeException)
116     {
117         ControlModelLock aLock( m_rControlModel );
118 
119         OSL_ENSURE( _rEvent.Source == m_xListSource,
120             "OEntryListHelper::entryRangeInserted: where did this come from?" );
121         OSL_ENSURE( ( _rEvent.Position > 0 ) && ( _rEvent.Position < m_aStringItems.getLength() ) && ( _rEvent.Entries.getLength() > 0 ),
122             "OEntryListHelper::entryRangeRemoved: invalid count and/or position!" );
123 
124         if  (   ( _rEvent.Position > 0 )
125             &&  ( _rEvent.Position < m_aStringItems.getLength() )
126             &&  ( _rEvent.Entries.getLength() > 0 )
127             )
128         {
129             // the entries *before* the insertion pos
130             Sequence< ::rtl::OUString > aKeepEntries(
131                 m_aStringItems.getConstArray(),
132                 _rEvent.Position
133             );
134             // the entries *behind* the insertion pos
135             Sequence< ::rtl::OUString > aMovedEntries(
136                 m_aStringItems.getConstArray() + _rEvent.Position,
137                 m_aStringItems.getLength() - _rEvent.Position
138             );
139 
140             // concat all three parts
141             m_aStringItems = ::comphelper::concatSequences(
142                 aKeepEntries,
143                 _rEvent.Entries,
144                 aMovedEntries
145             );
146 
147             stringItemListChanged( aLock );
148         }
149     }
150 
151     //---------------------------------------------------------------------
152     void SAL_CALL OEntryListHelper::entryRangeRemoved( const ListEntryEvent& _rEvent ) throw (RuntimeException)
153     {
154         ControlModelLock aLock( m_rControlModel );
155 
156         OSL_ENSURE( _rEvent.Source == m_xListSource,
157             "OEntryListHelper::entryRangeRemoved: where did this come from?" );
158         OSL_ENSURE( ( _rEvent.Position > 0 ) && ( _rEvent.Count > 0 ) && ( _rEvent.Position + _rEvent.Count <= m_aStringItems.getLength() ),
159             "OEntryListHelper::entryRangeRemoved: invalid count and/or position!" );
160 
161         if  (   ( _rEvent.Position > 0 )
162             &&  ( _rEvent.Count > 0 )
163             &&  ( _rEvent.Position + _rEvent.Count <= m_aStringItems.getLength() )
164             )
165         {
166             // copy all items after the removed ones
167             ::std::copy(
168                 m_aStringItems.getConstArray() + _rEvent.Position + _rEvent.Count,
169                 m_aStringItems.getConstArray() + m_aStringItems.getLength(),
170                 m_aStringItems.getArray( ) + _rEvent.Position
171             );
172             // shrink the array
173             m_aStringItems.realloc( m_aStringItems.getLength() - _rEvent.Count );
174 
175             stringItemListChanged( aLock );
176         }
177     }
178 
179     //---------------------------------------------------------------------
180     void SAL_CALL OEntryListHelper::allEntriesChanged( const EventObject& _rEvent ) throw (RuntimeException)
181     {
182         ControlModelLock aLock( m_rControlModel );
183 
184         OSL_ENSURE( _rEvent.Source == m_xListSource,
185             "OEntryListHelper::allEntriesChanged: where did this come from?" );
186 
187         Reference< XListEntrySource > xSource( _rEvent.Source, UNO_QUERY );
188         if ( _rEvent.Source == m_xListSource )
189         {
190             impl_lock_refreshList( aLock );
191         }
192     }
193 
194     // XRefreshable
195     //------------------------------------------------------------------------------
196     void SAL_CALL OEntryListHelper::addRefreshListener(const Reference<XRefreshListener>& _rxListener) throw(RuntimeException)
197     {
198         if ( _rxListener.is() )
199             m_aRefreshListeners.addInterface( _rxListener );
200     }
201 
202     //------------------------------------------------------------------------------
203     void SAL_CALL OEntryListHelper::removeRefreshListener(const Reference<XRefreshListener>& _rxListener) throw(RuntimeException)
204     {
205         if ( _rxListener.is() )
206             m_aRefreshListeners.removeInterface( _rxListener );
207     }
208 
209     //------------------------------------------------------------------------------
210     void SAL_CALL OEntryListHelper::refresh() throw(RuntimeException)
211     {
212         {
213             ControlModelLock aLock( m_rControlModel );
214             impl_lock_refreshList( aLock );
215         }
216 
217         EventObject aEvt( static_cast< XRefreshable* >( this ) );
218         m_aRefreshListeners.notifyEach( &XRefreshListener::refreshed, aEvt );
219     }
220 
221     //---------------------------------------------------------------------
222     void OEntryListHelper::impl_lock_refreshList( ControlModelLock& _rInstanceLock )
223     {
224         if ( hasExternalListSource() )
225         {
226             m_aStringItems = m_xListSource->getAllListEntries( );
227             stringItemListChanged( _rInstanceLock );
228         }
229         else
230             refreshInternalEntryList();
231     }
232 
233     //---------------------------------------------------------------------
234     bool OEntryListHelper::handleDisposing( const EventObject& _rEvent )
235     {
236         if ( m_xListSource .is() && ( _rEvent.Source == m_xListSource ) )
237         {
238             disconnectExternalListSource( );
239             return true;
240         }
241         return false;
242     }
243 
244     //---------------------------------------------------------------------
245     void OEntryListHelper::disposing( )
246     {
247         EventObject aEvt( static_cast< XRefreshable* >( this ) );
248         m_aRefreshListeners.disposeAndClear(aEvt);
249 
250         if ( hasExternalListSource( ) )
251             disconnectExternalListSource( );
252     }
253 
254     //---------------------------------------------------------------------
255     void OEntryListHelper::disconnectExternalListSource( )
256     {
257         if ( m_xListSource.is() )
258             m_xListSource->removeListEntryListener( this );
259 
260         m_xListSource.clear();
261 
262         disconnectedExternalListSource();
263     }
264 
265     //---------------------------------------------------------------------
266     void OEntryListHelper::connectedExternalListSource( )
267     {
268         // nothing to do here
269     }
270 
271     //---------------------------------------------------------------------
272     void OEntryListHelper::disconnectedExternalListSource( )
273     {
274         // nothing to do here
275     }
276 
277     //---------------------------------------------------------------------
278     void OEntryListHelper::connectExternalListSource( const Reference< XListEntrySource >& _rxSource, ControlModelLock& _rInstanceLock )
279     {
280         OSL_ENSURE( !hasExternalListSource(), "OEntryListHelper::connectExternalListSource: only to be called if no external source is active!" );
281         OSL_ENSURE( _rxSource.is(), "OEntryListHelper::connectExternalListSource: invalid list source!" );
282 
283         // remember it
284         m_xListSource = _rxSource;
285 
286         // initially fill our item list
287         if ( m_xListSource.is() )
288         {
289             // be notified when the list changes ...
290             m_xListSource->addListEntryListener( this );
291 
292             m_aStringItems = m_xListSource->getAllListEntries( );
293             stringItemListChanged( _rInstanceLock );
294 
295             // let derivees react on the new list source
296             connectedExternalListSource();
297         }
298     }
299 
300     //---------------------------------------------------------------------
301     sal_Bool OEntryListHelper::convertNewListSourceProperty( Any& _rConvertedValue,
302         Any& _rOldValue, const Any& _rValue ) SAL_THROW( ( IllegalArgumentException ) )
303     {
304         if ( hasExternalListSource() )
305             throw IllegalArgumentException( );
306             // TODO: error message
307 
308         return ::comphelper::tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, m_aStringItems );
309     }
310 
311     //---------------------------------------------------------------------
312     void OEntryListHelper::setNewStringItemList( const ::com::sun::star::uno::Any& _rValue, ControlModelLock& _rInstanceLock )
313     {
314         OSL_PRECOND( !hasExternalListSource(), "OEntryListHelper::setNewStringItemList: this should never have survived convertNewListSourceProperty!" );
315         OSL_VERIFY( _rValue >>= m_aStringItems );
316         stringItemListChanged( _rInstanceLock );
317     }
318 
319 //.........................................................................
320 }   // namespace frm
321 //.........................................................................
322