1 /*************************************************************************
2  *
3  *  The Contents of this file are made available subject to the terms of
4  *  the BSD license.
5  *
6  *  Copyright 2000, 2010 Oracle and/or its affiliates.
7  *  All rights reserved.
8  *
9  *  Redistribution and use in source and binary forms, with or without
10  *  modification, are permitted provided that the following conditions
11  *  are met:
12  *  1. Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *  2. Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *  3. Neither the name of Sun Microsystems, Inc. nor the names of its
18  *     contributors may be used to endorse or promote products derived
19  *     from this software without specific prior written permission.
20  *
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  *************************************************************************/
34 
35 import com.sun.star.uno.*;
36 import com.sun.star.lang.*;
37 import com.sun.star.container.*;
38 import com.sun.star.beans.*;
39 import com.sun.star.form.*;
40 import com.sun.star.util.*;
41 import com.sun.star.sdbc.*;
42 
43 
44 /**************************************************************************/
45 /** A helper class for recursively locking control models which are bound
46 	to a specific field
47 */
48 
49 class LockControlModels extends ComponentTreeTraversal
50 {
51 	private String	m_sDataField;
52 	private Boolean	m_aLockIt;
53 	private int		m_nLevel;	// nesting level relative to the form we started with
54 
55 	/* ------------------------------------------------------------------ */
56 	public LockControlModels( String sDataField, boolean bLockIt )
57 	{
58 		m_sDataField = sDataField;
59 		m_aLockIt = new Boolean( bLockIt );
60 		m_nLevel = 0;
61 	}
62 
63 	/* ------------------------------------------------------------------ */
64 	protected boolean shouldStepInto( XIndexContainer xContainer ) throws com.sun.star.uno.Exception
65 	{
66 		if ( !super.shouldStepInto( xContainer ) )
67 			return false;	// don't try to be more clever than our base class
68 
69 		XForm xForm = (XForm)UnoRuntime.queryInterface( XForm.class, xContainer );
70 		if ( ( null != xForm ) && ( m_nLevel > 1 ) )
71 			// don't step into sub forms - we only handle the form we were originally
72 			// applied to
73 			return false;
74 
75 		return true;
76 	}
77 
78 	/* ------------------------------------------------------------------ */
79 	public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception
80 	{
81 		// entering this nesting level
82 		++m_nLevel;
83 
84 		// check if the component has a DataField property
85 		XPropertySet xCompProps = UNO.queryPropertySet( aFormComponent );
86 		XPropertySetInfo xPSI = null;
87 		if ( null != xCompProps )
88 			xPSI = xCompProps.getPropertySetInfo();
89 
90 		if ( ( null != xPSI ) && xPSI.hasPropertyByName( "DataField" ) )
91 		{	// indeed it has ....
92 			String sDataField = (String)xCompProps.getPropertyValue( "DataField" );
93 			if ( sDataField.equals( m_sDataField ) )
94 			{	// we found a control model which is bound to what we're looking for
95 				xCompProps.setPropertyValue( "ReadOnly", m_aLockIt );
96 			}
97 		}
98 
99 		// allow the super class to step down, if possible
100 		super.handle( aFormComponent );
101 
102 		// leaving this nesting level
103 		--m_nLevel;
104 	}
105 };
106 
107 /**************************************************************************/
108 /** a class which automatically handles control locking.
109 	<p>The class has to be bound to a form. Upon every movement of the form,
110 	all controls which are bound to a (to be specified) field are locked
111 	on existing and unlocked on new records.</p>
112 */
113 class ControlLock implements XRowSetListener
114 {
115 	private	XPropertySet	m_xForm;
116 	private	String			m_sDataField;
117 	private boolean			m_bLockingEnabled;
118 	private boolean			m_bPreviousRoundLock;
119 
120 	/* ------------------------------------------------------------------ */
121 	ControlLock( XPropertySet xForm, String sBoundDataField )
122 	{
123 		m_xForm = xForm;
124 		m_sDataField = sBoundDataField;
125 		m_bLockingEnabled = false;
126 		m_bPreviousRoundLock = false;
127 	}
128 
129 	/* ------------------------------------------------------------------ */
130 	/** updates the locks on the affected controls
131 	*/
132 	protected void updateLocks( )
133 	{
134 		try
135 		{
136 			// first determine if we need to lock
137 			Boolean aIsNewRecord = (Boolean)m_xForm.getPropertyValue( "IsNew" );
138 
139 			boolean bNeedLock = m_bLockingEnabled && !aIsNewRecord.booleanValue();
140 
141 			if ( m_bPreviousRoundLock != bNeedLock )
142 			{
143 				LockControlModels aLocker = new LockControlModels( m_sDataField, bNeedLock );
144 				aLocker.handle( m_xForm );
145 				m_bPreviousRoundLock = bNeedLock;
146 			}
147 
148 			// please note that we choose the expensive way here: We always loop through
149 			// _all_ control models belonging to the form. This clearly slows down the
150 			// whole process.
151 			// A better solution would be to cache the affected control models. Then we
152 			// could either rely on the fact that the model hierarchy is static, or we
153 			// could add ourself as container listener to the form.
154 		}
155 		catch(com.sun.star.uno.Exception e)
156 		{
157 			System.out.println(e);
158 			e.printStackTrace();
159 		}
160 	}
161 
162 	/* ------------------------------------------------------------------ */
163 	/** enables the locking in general
164 		<p>If the control models are really locked depends on the current
165 		record of the form: on the insert row, controls are never locked.</p>
166 	*/
167 	public void enableLock( boolean bLock )
168 	{
169 		// remember this new setting
170 		m_bLockingEnabled = bLock;
171 
172 		// add or remove ourself as listener to get notified of cursor moves
173 		XRowSet xRowSet = (XRowSet)UnoRuntime.queryInterface(
174 			XRowSet.class, m_xForm );
175 		if ( m_bLockingEnabled )
176 		{
177 			xRowSet.addRowSetListener( this );
178 		}
179 		else
180 		{
181 			xRowSet.removeRowSetListener( this );
182 		}
183 
184 		// update the locks
185 		updateLocks();
186 	}
187 
188 	/* ==================================================================
189 	   = UNO callbacks
190 	   ================================================================== */
191 
192 	/* ------------------------------------------------------------------ */
193 	// XResetListener overridables
194 	/* ------------------------------------------------------------------ */
195 	public void cursorMoved( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
196 	{
197 		updateLocks( );
198 	}
199 
200 	/* ------------------------------------------------------------------ */
201 	public void rowChanged( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
202 	{
203 		// not interested in
204 	}
205 
206 	/* ------------------------------------------------------------------ */
207 	public void rowSetChanged( EventObject aEvent ) throws com.sun.star.uno.RuntimeException
208 	{
209 		// not interested in
210 	}
211 
212 	/* ------------------------------------------------------------------ */
213 	// XEventListener overridables
214 	/* ------------------------------------------------------------------ */
215 	public void disposing( EventObject aEvent )
216 	{
217 		// not interested in
218 	}
219 }
220