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 #include "proplist.hxx"
25 
26 #include <rtl/ustrbuf.hxx>
27 #include <toolkit/dllapi.h>
28 #include <com/sun/star/awt/WindowAttribute.hpp>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/awt/XVclWindowPeer.hpp>
31 #include <com/sun/star/awt/VclWindowPeerAttribute.hpp>
32 #include <tools/debug.hxx>
33 
34 #include "helper.hxx"
35 
36 #if TEST_LAYOUT && !defined( DBG_UTIL )
37 #undef DBG_ERROR
38 #define DBG_ERROR OSL_TRACE
39 #undef DBG_ERROR1
40 #define DBG_ERROR1 OSL_TRACE
41 #undef DBG_ERROR2
42 #define DBG_ERROR2 OSL_TRACE
43 #endif /* TEST_LAYOUT && !DBG_UTIL */
44 
45 namespace layoutimpl
46 {
47 
48 using namespace com::sun::star;
49 using rtl::OString;
50 using rtl::OUString;
51 using rtl::OUStringBuffer;
52 
53 namespace prophlp
54 {
55 
56 bool TOOLKIT_DLLPUBLIC
canHandleProps(const uno::Reference<uno::XInterface> & xPeer)57 canHandleProps( const uno::Reference< uno::XInterface > &xPeer )
58 {
59     uno::Reference< beans::XPropertySet > xPropSet( xPeer, uno::UNO_QUERY );
60     if ( xPropSet.is() )
61         return true;
62     uno::Reference< beans::XPropertySetInfo > xInfo( xPeer, uno::UNO_QUERY );
63     uno::Reference< awt::XVclWindowPeer> xVclPeer( xPeer, uno::UNO_QUERY );
64     return xInfo.is() && xVclPeer.is();
65 }
66 
67 uno::Reference< beans::XPropertySetInfo > TOOLKIT_DLLPUBLIC
queryPropertyInfo(const uno::Reference<uno::XInterface> & xPeer)68 queryPropertyInfo(
69     const uno::Reference< uno::XInterface > &xPeer )
70 {
71     uno::Reference< beans::XPropertySetInfo > xInfo( xPeer, uno::UNO_QUERY );
72     if ( !xInfo.is() )
73     {
74         uno::Reference< beans::XPropertySet > xPropSet( xPeer, uno::UNO_QUERY );
75         if ( xPropSet.is() )
76             xInfo = xPropSet->getPropertySetInfo();
77     }
78     return xInfo;
79 }
80 
81 void TOOLKIT_DLLPUBLIC
setProperty(const uno::Reference<uno::XInterface> & xPeer,const OUString & rName,uno::Any aValue)82 setProperty( const uno::Reference< uno::XInterface > &xPeer,
83                   const OUString &rName, uno::Any aValue )
84 {
85     uno::Reference< awt::XVclWindowPeer> xVclPeer( xPeer, uno::UNO_QUERY );
86     if ( xVclPeer.is() )
87         xVclPeer->setProperty( rName, aValue );
88     else
89     {
90         uno::Reference< beans::XPropertySet > xPropSet( xPeer, uno::UNO_QUERY );
91         xPropSet->setPropertyValue( rName, aValue );
92     }
93 }
94 
95 uno::Any TOOLKIT_DLLPUBLIC
getProperty(const uno::Reference<uno::XInterface> & xPeer,const OUString & rName)96 getProperty( const uno::Reference< uno::XInterface > &xPeer,
97                       const OUString &rName )
98 {
99     uno::Reference< awt::XVclWindowPeer> xVclPeer( xPeer, uno::UNO_QUERY );
100     if ( xVclPeer.is() )
101         return xVclPeer->getProperty( rName );
102 
103     uno::Reference< beans::XPropertySet > xPropSet( xPeer, uno::UNO_QUERY );
104     return xPropSet->getPropertyValue( rName );
105 }
106 
107 } // namespace prophlp
108 
109 
110 /* Given a string and a type, it converts the string to the type, and returns
111    it encapsulated in Any. */
anyFromString(OUString const & value,uno::Type const & type)112 uno::Any anyFromString( OUString const& value, uno::Type const& type )
113 {
114     sal_Int16 radix = 10;
115     OUString intval = value;
116     if ( value.getLength() > 2 && value[0] == '0' && value[1] == 'x' )
117         intval = value.copy( 2 ), radix = 16;
118     else if ( value.getLength() > 1 && value[0] == '#' )
119         intval = value.copy( 1 ), radix = 16;
120     switch ( type.getTypeClass() )
121     {
122         case uno::TypeClass_CHAR:
123             return uno::makeAny( value.toChar() );
124         case uno::TypeClass_BOOLEAN:
125             if ( value == OUString( RTL_CONSTASCII_USTRINGPARAM( "true" ) ) )
126                 return uno::makeAny( true );
127             else if ( value == OUString( RTL_CONSTASCII_USTRINGPARAM( "false" ) ) )
128                 return uno::makeAny( false );
129             break;  // ends switch, throws exception
130         case uno::TypeClass_BYTE:
131             return uno::makeAny( ( sal_uInt8 ) intval.toInt32( radix ) );
132         case uno::TypeClass_SHORT:
133             return uno::makeAny( ( sal_Int16 ) intval.toInt32( radix ) );
134         case uno::TypeClass_UNSIGNED_SHORT:
135             return uno::makeAny( ( sal_uInt16 ) intval.toInt32( radix ) );
136         case uno::TypeClass_ENUM:
137             return uno::makeAny( ( sal_Int16 ) intval.toInt32( radix ) );
138         case uno::TypeClass_LONG:
139             return uno::makeAny( ( sal_Int32 ) intval.toInt32( radix ) );
140         case uno::TypeClass_UNSIGNED_LONG:
141             return uno::makeAny( ( sal_uInt32 ) intval.toInt32( radix ) );
142         case uno::TypeClass_HYPER:
143             return uno::makeAny( ( sal_Int64 ) intval.toInt64( radix ) );
144         case uno::TypeClass_UNSIGNED_HYPER:
145             return uno::makeAny( ( sal_uInt16 ) intval.toInt64( radix ) );
146         case uno::TypeClass_FLOAT:
147             return uno::makeAny( value.toFloat() );
148         case uno::TypeClass_DOUBLE:
149             return uno::makeAny( value.toDouble() );
150         case uno::TypeClass_STRING:
151             return uno::makeAny( value );
152         case uno::TypeClass_CONSTANT:
153             return uno::makeAny( intval.toInt32( radix ) );
154         case uno::TypeClass_INTERFACE:
155             return uno::makeAny( loadGraphic( OUSTRING_CSTR( value ) ) );
156         case uno::TypeClass_SEQUENCE:
157         {
158             sal_Int32 i = 0;
159             bool escaped = false, first = true;
160             OUString item, token;
161             std::list< OUString > values;
162             do
163             {
164                 token = value.getToken( 0, ':', i );
165 
166                 if ( !token.getLength() && !escaped )
167                 {
168                     escaped = true;
169                     item += OUString( ':' );
170                 }
171                 else if ( escaped )
172                 {
173                     escaped = false;
174                     item += token;
175                 }
176                 else
177                 {
178                     if ( !first )
179                         values.push_back( item );
180                     item = token;
181                 }
182                 first = false;
183             }
184             while ( i >= 0 );
185             if ( item.getLength() )
186                 values.push_back( item );
187 
188             uno::Sequence< OUString > seq( values.size() );
189             i = 0;
190             for ( std::list< OUString >::const_iterator it = values.begin();
191                   it != values.end(); it++, i++ )
192                 seq[ i ] = *it;
193 
194             return uno::makeAny( seq );
195         }
196 
197         default:
198             DBG_ERROR1( "ERROR: unknown property type of value: `%s'\n", OUSTRING_CSTR( value ) );
199             break;
200     }
201     throw uno::RuntimeException();
202 }
203 
204 /* Converts the XML naming scheme to UNO's, for legacy compatibility
205    (so, ergo, "one-two-three-four" -> "OneTwoThreeFour"). */
toUnoNaming(OUString const & string)206 static OUString toUnoNaming ( OUString const &string )
207 {
208     OUStringBuffer buffer( string.getLength() );
209     sal_Unicode *str = string.pData->buffer;
210     bool capitalize = true;
211 
212     for ( int i = 0; i < string.getLength(); i++ )
213     {
214         if ( i == 0 && str[0] == '_' )
215             /* Skip translate-me prefix.  */
216             continue;
217         if ( str[i] == '-' )
218             capitalize = true;
219         else
220         {
221             if ( capitalize && str[i] >= 'a' && str[i] <= 'z' )
222                 buffer.append( (sal_Unicode ) ( str[i] - 'a' + 'A' ) );
223             else
224                 buffer.append( (sal_Unicode ) str[i] );
225             capitalize = false;
226         }
227     }
228 
229     return buffer.makeStringAndClear();
230 }
231 
232 /*
233  * convert incoming XML style property names, to AWT style property names.
234  * convert the values based on introspection information.
235  * apply to either an XPropertySet or an XPropertySetInfo | XVclWindowPeer
236  * aggregate.
237  */
238 void
setProperties(uno::Reference<uno::XInterface> const & xPeer,PropList const & rProps)239 setProperties( uno::Reference< uno::XInterface > const& xPeer,
240                PropList const& rProps )
241 {
242     if ( !prophlp::canHandleProps( xPeer ) )
243     {
244         DBG_ERROR( "Error: setProperties - bad handle ignoring props:\n" );
245         for ( PropList::const_iterator it = rProps.begin(); it != rProps.end();
246               it++ )
247         {
248             DBG_ERROR2( "%s=%s\n", OUSTRING_CSTR( it->first ), OUSTRING_CSTR( it->second ) );
249         }
250         return;
251     }
252 
253     for ( PropList::const_iterator it = rProps.begin(); it != rProps.end();
254           it++ )
255         setProperty( xPeer, it->first, it->second );
256 }
257 
258 void
setProperty(uno::Reference<uno::XInterface> const & xPeer,OUString const & attr,OUString const & value)259 setProperty( uno::Reference< uno::XInterface > const& xPeer,
260              OUString const& attr, OUString const& value )
261 {
262     OUString unoAttr = toUnoNaming( attr );
263 
264     OSL_TRACE( "setting %s=%s", OUSTRING_CSTR( attr ), OUSTRING_CSTR( value ) );
265     // get a Property object
266     beans::Property prop;
267     try
268     {
269         uno::Reference< beans::XPropertySetInfo > xInfo
270             = prophlp::queryPropertyInfo( xPeer );
271         prop = xInfo->getPropertyByName( unoAttr );
272     }
273     catch( beans::UnknownPropertyException & )
274     {
275         DBG_ERROR1( "Warning: unknown attribute: `%s'\n", OUSTRING_CSTR( unoAttr ) );
276         return;
277     }
278 
279     if ( prop.Name.getLength() <= 0 )
280     {
281         DBG_ERROR1( "Warning: missing prop: `%s'\n", OUSTRING_CSTR( unoAttr ) );
282         return;
283     }
284 
285     // encapsulates value in an uno::Any
286     uno::Any any;
287     try
288     {
289         any = anyFromString( value, prop.Type );
290     }
291     catch( uno::RuntimeException & )
292     {
293         DBG_ERROR5( "Warning: %s( %s )( %s ) attribute is of type %s( rejected: %s )\n", OUSTRING_CSTR( unoAttr ), OUSTRING_CSTR( value ), OUSTRING_CSTR( prop.Name ),  OUSTRING_CSTR( prop.Type.getTypeName() ), OUSTRING_CSTR( value ) );
294         return;
295     }
296 
297     // sets value on property
298     try
299     {
300         prophlp::setProperty( xPeer, unoAttr, any );
301     }
302     catch( ... )
303     {
304         DBG_ERROR2( "Warning: cannot set attribute %s to %s \n", OUSTRING_CSTR( unoAttr ), OUSTRING_CSTR( value ) );
305     }
306 }
307 
308 
309 
310 
311 struct AttributesMap
312 {
313     const char *name;
314     long value;
315     bool windowAttr;
316 };
317 static const AttributesMap attribsMap[] =
318 {
319     { "autohscroll",  awt::VclWindowPeerAttribute::AUTOHSCROLL,  false },
320     { "autovscroll",  awt::VclWindowPeerAttribute::AUTOVSCROLL,  false },
321     { "center",       awt::VclWindowPeerAttribute::CENTER,       false },
322     { "clipchildren", awt::VclWindowPeerAttribute::CLIPCHILDREN, false },
323     { "closeable",    awt::WindowAttribute::CLOSEABLE,           true },
324     { "defbutton",    awt::VclWindowPeerAttribute::DEFBUTTON,    false },
325     { "dropdown",     awt::VclWindowPeerAttribute::DROPDOWN,     false },
326     { "fullsize",     awt::WindowAttribute::FULLSIZE,            true  }, //FIXME?
327     { "group",        awt::VclWindowPeerAttribute::GROUP,        false },
328     { "has_border",   awt::WindowAttribute::BORDER,              true },
329     { "hscroll",      awt::VclWindowPeerAttribute::HSCROLL,      false },
330     { "left",         awt::VclWindowPeerAttribute::LEFT,         false },
331     { "moveable",     awt::WindowAttribute::MOVEABLE,            true },
332     { "noborder",     awt::VclWindowPeerAttribute::NOBORDER,     false },
333     { "nolabel",      awt::VclWindowPeerAttribute::NOLABEL,      false },
334     { "optimumsize",  awt::WindowAttribute::OPTIMUMSIZE,         false },
335     { "readonly",     awt::VclWindowPeerAttribute::READONLY,     false },
336     { "right",        awt::VclWindowPeerAttribute::RIGHT,        false },
337     { "show",         awt::WindowAttribute::SHOW,                true },
338     { "sizeable",     awt::WindowAttribute::SIZEABLE,            true },
339     { "sort",         awt::VclWindowPeerAttribute::SORT,         false },
340     { "spin",         awt::VclWindowPeerAttribute::SPIN,         false },
341     { "vscroll",      awt::VclWindowPeerAttribute::VSCROLL,      false },
342 
343     // cutting on OK, YES_NO_CANCEL and related obsite attributes...
344 };
345 static const int attribsMapLen = sizeof( attribsMap ) / sizeof( AttributesMap );
346 
347 #if 0
348 long getAttribute( const OUString &rName, bool bTopWindow )
349 {
350 
351     int min = 0, max = attribsMapLen - 1, mid, cmp;
352     do
353     {
354         mid = min +( max - min )/2;
355         cmp = rName.compareToAscii( attribsMap[ mid ].name );
356         if ( cmp > 0 )
357             min = mid+1;
358         else if ( cmp < 0 )
359             max = mid-1;
360         else
361         {
362             if ( bTopWindow || attribsMap[ mid ].value )
363                 return attribsMap[ mid ].windowAttr;
364             return 0;
365         }
366     }
367     while ( min <= max );
368     return 0;
369 }
370 #endif
371 
propsFromAttributes(const uno::Reference<xml::input::XAttributes> & xAttributes,PropList & rProps,sal_Int32 nNamespace)372 void propsFromAttributes( const uno::Reference<xml::input::XAttributes> & xAttributes,
373                           PropList &rProps, sal_Int32 nNamespace )
374 {
375     sal_Int32 nAttrs = xAttributes->getLength();
376     for ( sal_Int32 i = 0; i < nAttrs; i++ )
377     {
378         if ( nNamespace != xAttributes->getUidByIndex( i ) )
379             continue;
380 
381         std::pair< OUString, OUString > aElem
382             ( xAttributes->getLocalNameByIndex( i ),
383               xAttributes->getValueByIndex( i ) );
384 
385         if ( aElem.first.getLength() > 0 ) // namespace bits ..
386             rProps.push_back( aElem );
387     }
388 }
389 
390 bool
findAndRemove(const char * pAttr,PropList & rProps,OUString & rValue)391 findAndRemove( const char *pAttr, PropList &rProps, OUString &rValue )
392 {
393     PropList::iterator it;
394     OUString aName = OUString::createFromAscii( pAttr );
395 
396     for ( it = rProps.begin(); it != rProps.end(); it++ )
397     {
398         if ( it->first.equalsIgnoreAsciiCase( aName )
399              || it->first.equalsIgnoreAsciiCase( OUString::createFromAscii ("_") + aName ) )
400         {
401             rValue = it->second;
402             rProps.erase( it );
403             return true;
404         }
405     }
406     rValue = OUString();
407     return false;
408 }
409 
410 long
getAttributeProps(PropList & rProps)411 getAttributeProps( PropList &rProps )
412 {
413     long nAttrs = 0;
414     OUString aValue;
415 
416     OUString trueStr( RTL_CONSTASCII_USTRINGPARAM( "true" ) );
417 
418     if ( findAndRemove( "show", rProps, aValue ) &&
419          aValue.equalsIgnoreAsciiCase(
420              OUString( RTL_CONSTASCII_USTRINGPARAM( "false" ) ) ) )
421         ;
422     else
423         nAttrs |= awt::WindowAttribute::SHOW;
424 
425     for ( int i = 0; i < attribsMapLen; i++ )
426     {
427         if ( findAndRemove( attribsMap[i].name, rProps, aValue ) )
428         {
429             if ( aValue.equalsIgnoreAsciiCase( trueStr ) )
430                 nAttrs |= attribsMap[i].value;
431         }
432     }
433 
434     if ( findAndRemove( "align", rProps, aValue ) )
435     {
436         sal_Int32 nVal = aValue.toInt32();
437 
438         if ( nVal == 0 /* PROPERTY_ALIGN_LEFT */ )
439             nAttrs |= awt::VclWindowPeerAttribute::LEFT;
440         else if ( nVal == 1 /* PROPERTY_ALIGN_CENTER */ )
441             nAttrs |= awt::VclWindowPeerAttribute::CENTER;
442         else if ( nVal == 2 )
443             nAttrs |= awt::VclWindowPeerAttribute::RIGHT;
444     }
445 
446     return nAttrs;
447 }
448 
449 }
450 
451