1 /* -*- Mode: Java; 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 import com.sun.star.uno.Type;
20 import com.sun.star.uno.UnoRuntime;
21 import com.sun.star.table.XCell;
22 import com.sun.star.util.XModifyListener;
23 import com.sun.star.text.XTextRange;
24 
25 /** a value binding to be connected to a form control
26 
27     This binding synchronizes the text contained in a table cell (which you must
28     pass upon construction) to the text in an XBindableValue.
29 
30     Well, in real it does not synchronize both directions. The ValueBinding
31     service has not much room for own activity: It allows notification of changes
32     in the own value, and it allows external instances to set the current value.
33 
34     Note that we implement this binding as a separate thread, which is (more or
35     less permanently) polling for a new text at the cell. This is unfortunate, but
36     sadly the Writer table cells do not support actively notifying changes in their
37     content to other interested parties.
38 */
39 public class TableCellTextBinding
40                 extends     java.lang.Thread
41                 implements  com.sun.star.form.binding.XValueBinding,
42                             com.sun.star.util.XModifyBroadcaster
43 {
44     private XTextRange  m_cellText;
45     private Object      m_writeSignal;
46     private String      m_newCellText;
47     private String      m_lastKnownCellText;
48     private boolean     m_haveNewCellText;
49     private java.util.List<XModifyListener>  m_listeners;
50 
51     /** Creates a new instance of TableCellTextBinding */
TableCellTextBinding( XCell cell )52     public TableCellTextBinding( XCell cell )
53     {
54         m_cellText = UnoRuntime.queryInterface( XTextRange.class, cell );
55 
56         m_newCellText = "";
57         m_listeners = new java.util.LinkedList<XModifyListener>();
58 
59         start();
60     }
61 
62     /** retrieves the list of data types which this binding can exchange
63     */
getSupportedValueTypes()64     public com.sun.star.uno.Type[] getSupportedValueTypes()
65     {
66         try
67         {
68             // well, only strings here ...
69             return new Type[] {
70                 getStringType()
71             };
72         }
73         catch( java.lang.Exception e )
74         {
75         }
76         return new Type[] { };
77     }
78 
79     /** retrieves the current value
80     */
getValue(com.sun.star.uno.Type type)81     public Object getValue(com.sun.star.uno.Type type) throws com.sun.star.form.binding.IncompatibleTypesException
82     {
83         if ( !type.equals( getStringType() ) )
84             throw new com.sun.star.form.binding.IncompatibleTypesException();
85 
86         return m_cellText.getString();
87     }
88 
89     /** sets a new value
90     */
setValue(Object obj)91     public void setValue(Object obj) throws com.sun.star.form.binding.IncompatibleTypesException
92     {
93         String text;
94         try
95         {
96             text = (String)obj;
97         }
98         catch( java.lang.ClassCastException e )
99         {
100             throw new com.sun.star.form.binding.IncompatibleTypesException();
101         }
102         // remember the new text
103         synchronized( m_newCellText )
104         {
105             m_newCellText = text;
106             m_haveNewCellText = true;
107         }
108         // and wake up the thread which is waiting for it
109         synchronized( m_writeSignal )
110         {
111             m_writeSignal.notify();
112         }
113     }
114 
115     /** determines whether a given value type is supported
116     */
supportsType(com.sun.star.uno.Type type)117     public boolean supportsType(com.sun.star.uno.Type type)
118     {
119         return type.equals( getStringType() );
120     }
121 
122     /** retrieves the UNO type for the string class
123     */
getStringType()124     private static final Type getStringType()
125     {
126         return new com.sun.star.uno.Type( String.class );
127     }
128 
129     /** runs the thread
130     */
131     @Override
run()132     public void run()
133     {
134         try
135         {
136             m_writeSignal = new Object();
137             while ( true )
138             {
139                 // go sleep a while
140                 synchronized( m_writeSignal )
141                 {
142                     m_writeSignal.wait( 200 );
143                 }
144 
145                 // if there's new text in the control, propagate it to the cell
146                 synchronized ( m_newCellText )
147                 {
148                     if ( m_haveNewCellText )
149                     {
150                         m_cellText.setString( m_newCellText );
151                         m_lastKnownCellText = m_newCellText;
152                     }
153                     m_haveNewCellText = false;
154                 }
155 
156                 // if there's new text in the cell, propagate it to the control
157                 String currentCellText = m_cellText.getString();
158                 if ( !currentCellText.equals( m_lastKnownCellText ) )
159                 {
160                     m_lastKnownCellText = currentCellText;
161                     // notify the modification
162                     synchronized( m_listeners )
163                     {
164                         com.sun.star.lang.EventObject eventSource = new com.sun.star.lang.EventObject( this );
165 
166                         java.util.Iterator<XModifyListener> loop = m_listeners.iterator();
167                         while ( loop.hasNext() )
168                         {
169                             loop.next().modified( eventSource );
170                         }
171                     }
172                 }
173             }
174         }
175         catch( java.lang.Exception e )
176         {
177             e.printStackTrace(System.err);
178         }
179     }
180 
addModifyListener(com.sun.star.util.XModifyListener xModifyListener)181     public void addModifyListener(com.sun.star.util.XModifyListener xModifyListener)
182     {
183         synchronized( m_listeners )
184         {
185             m_listeners.add( xModifyListener );
186         }
187     }
188 
removeModifyListener(com.sun.star.util.XModifyListener xModifyListener)189     public void removeModifyListener(com.sun.star.util.XModifyListener xModifyListener)
190     {
191         synchronized( m_listeners )
192         {
193             m_listeners.remove( xModifyListener );
194         }
195     }
196 
197 }
198 
199 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
200