update dev300-m58
[ooovba.git] / toolkit / workben / layout / editor.cxx
blobcb6732ad591db3516b231cf846d39aa37cc86a1d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: editor.cxx,v $
11 * $Revision: 1.3 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 #include "editor.hxx"
34 #undef NDEBUG
36 /*
37 #include <assert.h>
38 #include <stdio.h>
39 #include <string.h>
42 #include <cassert>
43 #include <cstdio>
44 #include <cstring>
45 #include <list>
46 #include <vector>
48 #include <com/sun/star/awt/WindowAttribute.hpp>
49 #include <com/sun/star/awt/XLayoutConstrains.hpp>
50 #include <com/sun/star/awt/XLayoutContainer.hpp>
51 #include <com/sun/star/awt/XToolkit.hpp>
52 #include <com/sun/star/awt/XVclWindowPeer.hpp>
53 #include <com/sun/star/awt/XWindow.hpp>
54 #include <com/sun/star/awt/XWindowPeer.hpp>
55 #include <rtl/strbuf.hxx>
56 #include <rtl/ustrbuf.hxx>
57 #include <toolkit/helper/property.hxx>
58 #include <vcl/lstbox.h>
60 using namespace layout::css;
62 using rtl::OUString;
64 // FIXME:
65 //#define FILEDLG
67 #include <layout/core/helper.hxx>
68 #include <layout/core/root.hxx>
69 #include <layout/core/helper.hxx>
71 // TODO: automatically generated
72 struct WidgetSpec {
73 const char *pLabel, *pName, *pIconName;
74 bool bIsContainer; };
75 static const WidgetSpec WIDGETS_SPECS[] = {
76 { "Label", "fixedtext" , "sc_label.png", false },
77 { "Button", "pushbutton" , "sc_pushbutton.png", false },
78 { "Radio Button", "radiobutton" , "sc_radiobutton.png", false },
79 { "Check Box", "checkbox" , "sc_checkbox.png", false },
80 { "Line Edit", "edit" , "sc_edit.png", false },
81 { "Numeric Field", "numericfield", "sc_numericfield.png", false },
82 { "List Box ", "listbox" , NULL, false },
83 // containers
84 { "Hor Box", "hbox" , NULL, true },
85 { "Ver Box", "vbox" , NULL, true },
86 { "Table", "table" , NULL, true },
87 { "Alignment", "align" , NULL, true },
88 { "Tab Control", "tabcontrol" , NULL, true },
89 { "Hor Splitter", "hsplitter" , NULL, true },
90 { "Ver Splitter", "vsplitter" , NULL, true },
91 { "Scroller", "scroller" , NULL, true },
93 const int WIDGETS_SPECS_LEN = sizeof (WIDGETS_SPECS) / sizeof (WidgetSpec);
95 using namespace layout;
96 using namespace layoutimpl;
97 namespace css = ::com::sun::star;
99 static rtl::OUString anyToString (uno::Any value)
103 switch (value.getValueTypeClass()) {
104 case uno::TypeClass_STRING:
105 return value.get<rtl::OUString>();
106 case uno::TypeClass_CONSTANT:
107 return rtl::OUString::valueOf (value.get<sal_Int32>());
108 case uno::TypeClass_LONG:
109 return rtl::OUString::valueOf (value.get<sal_Int64>());
110 case uno::TypeClass_SHORT:
111 // FIXME: seems broken
112 return rtl::OUString::valueOf ((sal_Int32) value.get<short>());
114 case uno::TypeClass_FLOAT:
115 return rtl::OUString::valueOf (value.get<float>());
116 case uno::TypeClass_DOUBLE:
117 return rtl::OUString::valueOf (value.get<double>());
119 case uno::TypeClass_BOOLEAN:
121 bool val = value.get<sal_Bool>();
122 return rtl::OUString( val ? "1" : "0", 1, RTL_TEXTENCODING_ASCII_US );
123 /* if ( val )
124 return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "true" ) );
125 else
126 return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "false" ) );*/
128 default:
129 break;
132 catch(...) {}
133 return rtl::OUString();
136 static inline long anyToNatural (uno::Any value)
137 { return sal::static_int_cast<long>(anyToString( value ).toInt64()); }
138 static inline double anyToDecimal (uno::Any value)
139 { return anyToString( value ).toDouble(); }
141 /* XLayoutContainer/XLayoutConstrains are a bit of a hasle to work with.
142 Let's wrap them. */
143 class Widget : public layoutimpl::LayoutWidget
145 friend class EditorRoot;
147 Widget *mpParent;
148 std::vector< Widget *> maChildren;
149 bool mbForeign;
151 rtl::OUString mrId;
152 rtl::OUString mrLabel, mrUnoName;
154 // TODO: store original properties. And some property handling methods.
155 long mnOriAttrbs;
156 layoutimpl::PropList maOriProps, maOriChildProps;
158 public:
160 // to be used to wrap the root
161 Widget( uno::Reference< awt::XLayoutConstrains > xImport, const char *label )
162 : mpParent( 0 ), mbForeign( true )
164 mxWidget = xImport;
165 mxContainer = uno::Reference< awt::XLayoutContainer >( mxWidget, uno::UNO_QUERY );
167 mrLabel = rtl::OUString( label, strlen( label ), RTL_TEXTENCODING_UTF8 );
169 #if 0 /* obsolete */
170 // FIXME: this code is meant to import a XML file. Just use the importer,
171 // then pass the root widget. But information like the ID string is lost.
172 // So, this needs to be more closely tight to the importer.
173 uno::Sequence< uno::Reference< awt::XLayoutConstrains > > aChildren;
174 for ( int i = 0; i < aChildren.getLength(); i++ )
176 Widget *pChild = new Widget( aChildren[ i ], "---" );
177 maChildren.push_back( pChild );
178 pChild->mpParent = this;
180 #endif
183 Widget( rtl::OUString id, uno::Reference< awt::XToolkit > xToolkit,
184 uno::Reference< awt::XLayoutContainer > xParent,
185 rtl::OUString unoName, long nAttrbs )
186 : mpParent( 0 ), mbForeign( false ), mrId( id ),
187 mnOriAttrbs( nAttrbs )
189 while ( xParent.is() && !uno::Reference< awt::XWindow >( xParent, uno::UNO_QUERY ).is() )
191 uno::Reference< awt::XLayoutContainer > xContainer( xParent, uno::UNO_QUERY );
192 assert( xContainer.is() );
193 xParent = uno::Reference< awt::XLayoutContainer >( xContainer->getParent(), uno::UNO_QUERY );
196 mxWidget = WidgetFactory::createWidget( xToolkit, xParent, unoName, nAttrbs );
197 assert( mxWidget.is() );
198 mxContainer = uno::Reference< awt::XLayoutContainer >( mxWidget, uno::UNO_QUERY );
200 mrLabel = mrUnoName = unoName;
201 // try to get a nicer label for the widget
202 for ( int i = 0; i < WIDGETS_SPECS_LEN; i++ )
203 if ( unoName.equalsAscii( WIDGETS_SPECS[ i ].pName ) )
205 const char *label = WIDGETS_SPECS[ i ].pLabel;
206 mrLabel = rtl::OUString( label, strlen( label ), RTL_TEXTENCODING_UTF8 );
207 break;
210 // set default Text property
211 // TODO: disable editing of text fields, check boxes selected, etc...
212 #if 0
213 uno::Reference< awt::XVclWindowPeer> xVclPeer( mxWidget, uno::UNO_QUERY )
214 if ( xVclPeer.is() ) // XVclWindowPeer ignores missing / incorrect properties
216 //FIXME: it looks odd on widgets like NumericField seeing text which is deleted
217 // when you interact with it... We can avoid it for those widgets, by doing a getProp
218 // of "Text" and check if it is empty or not.
220 xVclPeer->setProperty( rtl::OUString::createFromAscii( "Text" ),
221 uno::makeAny( rtl::OUString::createFromAscii( "new widget" ) ) );
222 #endif
224 // store original properties
226 PropertyIterator it( this, WINDOW_PROPERTY );
227 while ( it.hasNext() )
229 beans::Property prop = it.next();
230 rtl::OUString name( prop.Name );
231 rtl::OUString value( getProperty( name, WINDOW_PROPERTY ) );
232 #if DEBUG_PRINT
233 fprintf(stderr, "original property: %s = %s\n", OUSTRING_CSTR(name), OUSTRING_CSTR(value));
234 #endif
235 std::pair< rtl::OUString, rtl::OUString > pair( name, value );
236 maOriProps.push_back( pair );
242 ~Widget()
244 for ( std::vector< Widget *>::const_iterator it = maChildren.begin();
245 it != maChildren.end(); it++ )
246 delete *it;
247 if ( !mbForeign )
249 uno::Reference< lang::XComponent > xComp( mxWidget, uno::UNO_QUERY );
250 if ( xComp.is() )
251 // some widgets, like our containers, don't implement this interface...
252 xComp->dispose();
256 uno::Reference< awt::XLayoutConstrains > impl()
258 return mxWidget;
261 // LayoutWidget
262 virtual bool addChild( LayoutWidget *pChild )
264 return addChild( static_cast< Widget * >( pChild ) );
267 virtual void setProperties( const PropList &rProps )
269 // maOriProps = rProps;
270 LayoutWidget::setProperties( rProps );
273 virtual void setChildProperties( LayoutWidget *pChild, const PropList &rProps )
275 maOriChildProps = rProps;
276 LayoutWidget::setChildProperties( pChild, rProps );
279 // tree travel
280 Widget *up()
282 return mpParent;
285 Widget *down()
287 if ( maChildren.empty() )
288 return NULL;
289 return maChildren.front();
292 Widget *next()
294 if ( mpParent )
296 int pos = mpParent->getChildPos( this );
297 return mpParent->getChild( pos+1 );
299 return NULL;
302 Widget *prev()
304 if ( mpParent )
306 int pos = mpParent->getChildPos( this );
307 return mpParent->getChild( pos-1 );
309 return NULL;
312 // handle
313 bool addChild( Widget *pChild, int pos = 0xffff )
315 if ( !mxContainer.is() )
316 return false;
318 uno::Sequence< uno::Reference < awt::XLayoutConstrains > > aChildren;
319 aChildren = mxContainer->getChildren();
320 int nChildrenLen = aChildren.getLength();
322 // ugly, but let's check if the container is next to full...
323 try {
324 mxContainer->addChild( pChild->mxWidget );
326 catch( awt::MaxChildrenException ex ) {
327 return false;
330 if ( pos < nChildrenLen )
331 { // if its on the middle, we need to make space for it
332 mxContainer->removeChild( pChild->mxWidget );
333 for ( int i = pos; i < nChildrenLen; i++ )
334 mxContainer->removeChild( aChildren[ i ] );
335 mxContainer->addChild( pChild->mxWidget );
336 for ( int i = pos; i < nChildrenLen; i++ )
337 mxContainer->addChild( aChildren[ i ] );
338 maChildren.insert( maChildren.begin()+pos, pChild );
340 else
341 maChildren.push_back( pChild );
343 assert( pChild->mpParent == NULL );
344 pChild->mpParent = this;
346 // store container props
348 pChild->maOriChildProps.clear();
349 PropertyIterator it( pChild, CONTAINER_PROPERTY );
350 while ( it.hasNext() )
352 beans::Property prop = it.next();
353 rtl::OUString name( prop.Name );
354 try {
355 rtl::OUString value( pChild->getProperty( name, CONTAINER_PROPERTY ) );
356 std::pair< rtl::OUString, rtl::OUString > pair( name, value );
357 pChild->maOriChildProps.push_back( pair );
358 } catch ( beans::UnknownPropertyException &rEx ) {
359 fprintf (stderr, "ERROR: widget reports that it has a property it cannot return: '%s' this normally means that someone screwed up their PROPERTY_SET_INFO macro usage.\n",
360 rtl::OUStringToOString (rEx.Message, RTL_TEXTENCODING_UTF8).getStr());
365 return true;
368 bool removeChild( Widget *pChild )
370 if ( !mxContainer.is() || pChild->mpParent != this )
371 return false;
373 mxContainer->removeChild( pChild->mxWidget );
375 unsigned int pos = getChildPos( pChild );
376 if ( pos < maChildren.size() )
377 maChildren.erase( maChildren.begin()+pos );
378 pChild->mpParent = NULL;
380 return true;
383 bool swapWithChild( Widget *pChild )
385 if ( !pChild->isContainer() )
386 return false;
388 // remove all child's childrens, and try to add them here
389 removeChild( pChild );
391 // keep a copy for failure
392 std::vector< Widget *> aChildren = maChildren;
393 std::vector< Widget *> aChildChildren = pChild->maChildren;
395 for ( std::vector< Widget *>::const_iterator it = aChildChildren.begin();
396 it != aChildChildren.end(); it++ )
397 pChild->removeChild( *it );
399 for ( std::vector< Widget *>::const_iterator it = aChildChildren.begin();
400 it != aChildChildren.end(); it++ )
401 if ( !addChild( *it ) )
402 { // failure
403 for ( std::vector< Widget *>::const_iterator jt = aChildChildren.begin();
404 jt != it; jt++ )
405 removeChild( *jt );
406 for ( std::vector< Widget *>::const_iterator jt = aChildChildren.begin();
407 jt != aChildChildren.end(); jt++ )
408 pChild->addChild( *jt );
409 return false;
412 Widget *pParent = up();
414 if ( pParent )
416 pParent->removeChild( this );
417 pParent->addChild( pChild );
419 pChild->addChild( this );
420 return true;
423 unsigned int getChildPos( Widget *pChild )
425 int i = 0;
426 for ( std::vector< Widget *>::const_iterator it = maChildren.begin();
427 it != maChildren.end(); it++, i++ )
428 if ( *it == pChild )
429 break;
430 return i;
433 Widget *getChild( int pos )
435 if ( pos >= 0 && pos < (signed) maChildren.size() )
436 return *(maChildren.begin() + pos);
437 return NULL;
440 bool isContainer()
441 { return mxContainer.is(); }
442 unsigned int getChildrenLen()
443 { return maChildren.size(); }
445 rtl::OUString getLabel() const
446 { return mrLabel; }
447 rtl::OUString getUnoName() const
448 { return mrUnoName; }
450 int getDepth()
452 int depth = 0;
453 for ( Widget *pWidget = mpParent; pWidget; pWidget = pWidget->mpParent )
454 depth++;
455 return depth;
458 enum PropertyKind {
459 WINDOW_PROPERTY, CONTAINER_PROPERTY, WINBITS_PROPERTY
462 static rtl::OUString findProperty( const PropList &props, rtl::OUString propName )
464 for ( PropList::const_iterator it = props.begin(); it != props.end(); it++ )
465 if ( it->first.equalsIgnoreAsciiCase( propName ) )
466 return it->second;
467 #if DEBUG_PRINT
468 fprintf(stderr, "Serious error: property '%s' not found\n", OUSTRING_CSTR(propName));
469 #endif
470 return rtl::OUString();
473 rtl::OUString getOriginalProperty( rtl::OUString rPropName, PropertyKind rKind )
475 rtl::OUString rValue;
476 switch ( rKind ) {
477 case WINDOW_PROPERTY:
478 rValue = findProperty( maOriProps, rPropName );
479 break;
480 case CONTAINER_PROPERTY:
481 rValue = findProperty( maOriChildProps, rPropName );
482 break;
483 case WINBITS_PROPERTY:
484 // TODO
485 break;
488 return rValue;
491 rtl::OUString getProperty( rtl::OUString rPropName, PropertyKind rKind )
493 rtl::OUString rValue;
494 switch ( rKind ) {
495 case WINDOW_PROPERTY:
496 rValue = anyToString( layoutimpl::prophlp::getProperty( mxWidget, rPropName ) );
497 break;
498 case CONTAINER_PROPERTY:
499 if ( mpParent )
500 rValue = anyToString( layoutimpl::prophlp::getProperty(
501 mpParent->mxContainer->getChildProperties( mxWidget ), rPropName ) );
502 break;
503 case WINBITS_PROPERTY:
504 // TODO
505 break;
508 return rValue;
511 bool isPropertyTouched( rtl::OUString propName, PropertyKind rKind )
513 rtl::OUString oriValue = getOriginalProperty( propName, rKind );
514 rtl::OUString newValue = getProperty( propName, rKind );
515 bool isTouched = oriValue != newValue;
516 #if DEBUG_PRINT
517 fprintf(stderr, "is property '%s' touched? %s (%s vs %s)\n", OUSTRING_CSTR(propName), isTouched ? "yes" : "no", OUSTRING_CSTR(oriValue), OUSTRING_CSTR(newValue));
518 #endif
519 return isTouched;
522 using LayoutWidget::setProperty;
524 void setProperty( rtl::OUString rPropName, PropertyKind rKind, uno::Any rValue )
526 switch ( rKind ) {
527 case WINDOW_PROPERTY:
528 layoutimpl::prophlp::setProperty( mxWidget, rPropName, rValue );
529 break;
530 case CONTAINER_PROPERTY:
531 if ( mpParent )
532 layoutimpl::prophlp::setProperty(
533 mpParent->mxContainer->getChildProperties( mxWidget ), rPropName, rValue );
534 break;
535 case WINBITS_PROPERTY:
536 // TODO
537 break;
541 struct PropertyIterator {
542 friend class Widget;
543 PropertyKind mrKind;
544 uno::Sequence< beans::Property > maProps;
545 int nPropIt;
547 PropertyIterator( Widget *pWidget, PropertyKind rKind )
548 : mrKind( rKind ), nPropIt( 0 )
550 switch ( rKind )
552 case WINDOW_PROPERTY:
553 if ( layoutimpl::prophlp::canHandleProps( pWidget->mxWidget ) )
555 uno::Reference< beans::XPropertySetInfo > xInfo
556 = layoutimpl::prophlp::queryPropertyInfo( pWidget->mxWidget );
557 if ( !xInfo.is() )
558 return;
560 maProps = xInfo->getProperties();
562 break;
563 case CONTAINER_PROPERTY:
564 if ( pWidget->mpParent )
566 uno::Reference< beans::XPropertySet >xParentSet(
567 pWidget->mpParent->mxContainer->getChildProperties( pWidget->mxWidget ) );
568 if ( xParentSet.is())
570 uno::Reference< beans::XPropertySetInfo > xInfo( xParentSet->getPropertySetInfo() );
571 if ( xInfo.is() )
572 maProps = xInfo->getProperties();
575 break;
576 case WINBITS_PROPERTY:
577 // TODO
578 break;
582 bool hasNext()
584 return nPropIt < maProps.getLength();
587 beans::Property next()
589 /* rtl::OUString propName, propValue;
590 propName = maProps[ nPropIt ];
591 propValue = getProperty( propName, mrKind, false);
592 nPropIt++;
593 return std::pair< rtl::OUString, rtl::OUString > propPair( propName, propValue );*/
594 return maProps[ nPropIt++ ];
599 class EditorRoot : public layoutimpl::LayoutRoot {
600 Widget *mpParent;
602 public:
603 EditorRoot( const uno::Reference< lang::XMultiServiceFactory >& xFactory,
604 Widget *pParent )
605 : layoutimpl::LayoutRoot( xFactory ), mpParent( pParent )
609 // generation
610 virtual layoutimpl::LayoutWidget *create( rtl::OUString id, const rtl::OUString unoName,
611 long attrbs, uno::Reference< awt::XLayoutContainer > xParent )
613 if ( unoName.compareToAscii( "dialog" ) == 0 )
614 return mpParent;
616 // TODO: go through specs to map unoName to a more human-readable label
617 Widget *pWidget = new Widget( id, mxToolkit, xParent, unoName, attrbs );
618 if ( !mxWindow.is() )
619 mxWindow = uno::Reference< awt::XWindow >( pWidget->getPeer(), uno::UNO_QUERY );
621 if ( pWidget->mxContainer.is() )
622 pWidget->mxContainer->setLayoutUnit( mpParent->mxContainer->getLayoutUnit() );
624 return pWidget;
628 /* Working with the layout in 1D, as if it was a flat list. */
629 namespace FlatLayout
631 Widget *next( Widget *pWidget )
633 Widget *pNext;
634 pNext = pWidget->down();
635 if ( pNext ) return pNext;
636 pNext = pWidget->next();
637 if ( pNext ) return pNext;
638 for ( Widget *pUp = pWidget->up(); pUp != NULL; pUp = pUp->up() )
639 if ( (pNext = pUp->next()) != NULL )
640 return pNext;
641 return NULL;
645 Widget *prev( Widget *pWidget )
647 Widget *pPrev;
648 pPrev = pWidget->prev();
649 if ( !pPrev )
650 return pWidget->up();
652 Widget *pBottom = pPrev->down();
653 if ( pBottom )
655 while ( pBottom->down() || pBottom->next() )
657 for ( Widget *pNext = pBottom->next(); pNext; pNext = pNext->next() )
658 pBottom = pNext;
659 Widget *pDown = pBottom->down();
660 if ( pDown )
661 pBottom = pDown;
663 return pBottom;
665 return pPrev;
669 bool moveWidget( Widget *pWidget, bool up /*or down*/ )
671 // Keep child parent&pos for in case of failure
672 Widget *pOriContainer = pWidget->up();
673 unsigned int oriChildPos = pOriContainer->getChildPos( pWidget );
675 // Get parent&sibling before removing it, since relations get cut
676 Widget *pSibling = up ? pWidget->prev() : pWidget->next();
677 Widget *pContainer = pWidget->up();
678 if ( !pContainer )
679 return false;
681 // try to swap with parent or child
682 // We need to allow for this at least for the root node...
683 if ( !pSibling )
685 if ( up )
687 if ( pContainer->swapWithChild( pWidget ) )
688 return true;
690 else
692 // TODO: this is a nice feature, but we probably want to do it explicitely...
693 #if 0
694 if ( pWidget->down() && pWidget->swapWithChild( pWidget->down() ) )
695 return true;
696 #endif
700 pContainer->removeChild( pWidget );
702 // if has up sibling -- append to it, else swap with it
703 if ( pSibling )
705 if ( pSibling->addChild( pWidget, up ? 0xffff : 0 ) )
706 return true;
708 unsigned int childPos = pContainer->getChildPos( pSibling );
709 if ( pContainer->addChild( pWidget, childPos + (up ? 0 : 1) ) )
710 return true; // should always be succesful
712 // go through parents -- try to get prepended to them
713 else
715 for ( ; pContainer && pContainer->up(); pContainer = pContainer->up() )
717 unsigned int childPos = pContainer->up()->getChildPos( pContainer );
718 if ( pContainer->up()->addChild( pWidget, childPos + (up ? 0 : 1) ) )
719 return true;
723 // failed -- try to get it to its old position
724 if ( !pOriContainer->addChild( pWidget, oriChildPos ) )
726 // a parent should never reject a child back. but if it ever
727 // happens, just kill it, we don't run an orphanate here ;P
728 delete pWidget;
729 return true;
731 return false;
734 // NOTE: root is considered to be number -1
735 Widget *get( Widget *pRoot, int nb )
737 Widget *it;
738 for ( it = pRoot; it != NULL && nb >= 0; it = next( it ) )
739 nb--;
740 return it;
743 int get( Widget *pRoot, Widget *pWidget )
745 int nRet = -1;
746 Widget *it;
747 for ( it = pRoot; it != NULL && it != pWidget; it = next( it ) )
748 nRet++;
749 return nRet;
753 //** PropertiesList widget
755 class PropertiesList : public layout::Table
757 class PropertyEntry
759 friend class PropertiesList;
761 /* wrapper between the widget and Any */
762 struct AnyWidget
764 DECL_LINK( ApplyPropertyHdl, layout::Window* );
765 DECL_LINK( FlagToggledHdl, layout::CheckBox* );
767 AnyWidget( Widget *pWidget, rtl::OUString aPropName, Widget::PropertyKind aPropKind )
768 : mpWidget( pWidget ), maPropName( aPropName ), maPropKind( aPropKind )
770 mpFlag = 0;
771 mbBlockFlagCallback = false;
772 bFirstGet = true;
775 virtual ~AnyWidget()
777 #if DEBUG_PRINT
778 fprintf(stderr, "~AnyWidget\n");
779 #endif
782 void save( uno::Any aValue )
784 mpWidget->setProperty( maPropName, maPropKind, aValue );
785 checkProperty();
788 void checkProperty()
790 bool flag = mpWidget->isPropertyTouched( maPropName, maPropKind );
792 if ( mpFlag && mpFlag->IsChecked() != (BOOL)flag )
794 CheckFlag( flag, true );
798 void CheckFlag( bool bValue, bool bBlockCallback )
800 if ( bBlockCallback )
801 mbBlockFlagCallback = true;
802 mpFlag->Check( bValue );
803 mbBlockFlagCallback = false;
806 bool bFirstGet; // HACK
807 rtl::OUString getValue()
809 // return mpWidget->getOriProperty( maPropName );
810 rtl::OUString value;
811 if ( bFirstGet ) // king of ugliness
812 value = mpWidget->getProperty( maPropName, maPropKind );
813 else
814 value = mpWidget->getOriginalProperty( maPropName, maPropKind );
815 bFirstGet = false;
816 return value;
819 // FIXME: wrapper should have a base class for this...
820 virtual layout::Window *getWindow() = 0;
821 virtual layout::Container *getContainer() { return NULL; }
823 virtual void load() = 0;
824 virtual void store() = 0;
826 Widget *mpWidget;
827 rtl::OUString maPropName;
828 Widget::PropertyKind maPropKind;
829 layout::CheckBox *mpFlag;
830 bool mbBlockFlagCallback;
833 struct AnyEdit : public AnyWidget, layout::HBox
835 layout::Edit *mpEdit;
836 bool mbMultiLine;
837 layout::PushButton *mpExpand;
838 DECL_LINK( ExpandEditHdl, layout::PushButton* );
840 // so we can create widgets (like transforming the Edit into a
841 // MultiLineEdit)
842 layout::Window *mpWinParent;
844 AnyEdit( Widget *pWidget, rtl::OUString aPropName,
845 Widget::PropertyKind aPropKind, layout::Window *pWinParent )
846 : AnyWidget( pWidget, aPropName, aPropKind ), layout::HBox( 0, false ), mpWinParent( pWinParent )
848 mpEdit = NULL;
849 mpExpand = new layout::PushButton( pWinParent, WB_TOGGLE );
850 mpExpand->SetToggleHdl( LINK( this, AnyEdit, ExpandEditHdl ) );
851 setAsMultiLine( false );
853 load();
856 virtual ~AnyEdit()
858 delete mpEdit;
859 delete mpExpand;
862 virtual layout::Window *getWindow()
863 { return NULL; }
864 virtual layout::Container *getContainer()
865 { return this; }
867 void setAsMultiLine( bool bMultiLine )
869 Clear();
870 XubString text;
871 if ( mpEdit )
873 text = mpEdit->GetText();
874 printf("Remove mpEdit and expand\n");
875 Remove( mpEdit );
876 Remove( mpExpand );
877 delete mpEdit;
880 if ( bMultiLine )
882 mpEdit = new layout::Edit( mpWinParent, WB_BORDER );
883 mpExpand->SetText( String::CreateFromAscii( "-" ) );
885 else
887 mpEdit = new layout::Edit( mpWinParent, WB_BORDER );
888 mpExpand->SetText( String::CreateFromAscii( "+" ) );
891 mpEdit->SetText( text );
892 mpEdit->SetModifyHdl( LINK( this, AnyEdit, ApplyPropertyHdl ) );
894 Add( mpEdit, true, true, 0 );
895 Add( mpExpand, false, true, 0 );
897 mbMultiLine = bMultiLine;
900 #if 0
901 // TODO: make this global... We'll likely need it for export...
902 struct Translate {
903 const char *ori, *dest;
905 static rtl::OUString stringReplace( rtl::OUString _str,
906 Translate *trans )
908 const sal_Unicode *str = _str.getStr();
909 rtl::OUStringBuffer buf;
910 int i, j, k;
911 for ( i = 0; i < _str.getLength(); i++ )
913 for ( j = 0; trans[ j ].ori; j++ )
915 const char *ori = trans[ j ].ori;
916 for ( k = 0; ori[ k ] && i+k < _str.getLength(); k++ )
917 if ( ori[ k ] != str[ i+k ] )
918 break;
919 if ( !ori[ k ] )
921 // found substring
922 buf.appendAscii( trans[ j ].dest );
923 i += k;
924 continue;
927 buf.append( str[ i ] );
929 return buf.makeStringAndClear();
931 #endif
933 virtual void load()
935 #if 0
936 // replace end of lines by "\\n" strings
937 Translate trans[] = {
938 { "\\", "\\\\" }, { "\n", "\\n" }, { 0, 0 }
940 rtl::OUString str = anyToString( getValue() );
941 str = stringReplace( str, trans );
942 SetText( str );
943 #endif
944 mpEdit->SetText( getValue() );
945 checkProperty();
948 virtual void store()
950 #if 0
951 // replace "\\n" strings by actual end of lines
952 Translate trans[] = {
953 { "\\\\", "\\" }, { "\\n", "\n" },
954 { "\\", "" }, { 0, 0 }
956 rtl::OUString str = GetText();
957 str = stringReplace( str, trans );
958 save( uno::makeAny( str ) );
959 #endif
960 save( uno::makeAny( (rtl::OUString) mpEdit->GetText() ) );
964 struct AnyInteger : public AnyWidget, NumericField
966 AnyInteger( Widget *pWidget, rtl::OUString aPropName,
967 Widget::PropertyKind aPropKind, Window *pWinParent )
968 : AnyWidget( pWidget, aPropName, aPropKind ), NumericField( pWinParent, WB_SPIN|WB_BORDER )
970 load();
971 SetModifyHdl( LINK( this, AnyInteger, ApplyPropertyHdl ) );
974 virtual Window *getWindow()
975 { return this; }
977 virtual void load()
979 OUString text = getValue();
980 SetText( text.getStr() );
981 checkProperty();
984 virtual void store()
986 #if DEBUG_PRINT
987 fprintf(stderr, "store number: %ld\n", rtl::OUString( GetText() ).toInt64());
988 #endif
989 save( uno::makeAny( rtl::OUString( GetText() ).toInt64() ) );
993 struct AnyFloat : public AnyInteger
995 AnyFloat( Widget *pWidget, rtl::OUString aPropName,
996 Widget::PropertyKind aPropKind, Window *pWinParent )
997 : AnyInteger( pWidget, aPropName, aPropKind, pWinParent )
1000 virtual void store()
1002 save( uno::makeAny( rtl::OUString( GetText() ).toDouble() ) );
1006 struct AnyCheckBox : public AnyWidget, layout::CheckBox
1008 AnyCheckBox( Widget *pWidget, rtl::OUString aPropName,
1009 Widget::PropertyKind aPropKind, layout::Window *pWinParent )
1010 : AnyWidget( pWidget, aPropName, aPropKind ), layout::CheckBox( pWinParent )
1012 // adding some whitespaces to make the hit area larger
1013 // SetText( String::CreateFromAscii( "" ) );
1014 load();
1015 SetToggleHdl( LINK( this, AnyWidget, ApplyPropertyHdl ) );
1018 virtual ~AnyCheckBox()
1020 #if DEBUG_PRINT
1021 fprintf(stderr, "~AnyCheckBox\n");
1022 #endif
1025 virtual layout::Window *getWindow()
1026 { return this; }
1028 virtual void load()
1030 #if DEBUG_PRINT
1031 fprintf(stderr, "loading boolean value\n");
1032 #endif
1033 Check( getValue().toInt64() != 0 );
1034 setLabel();
1035 checkProperty();
1038 virtual void store()
1040 save( uno::makeAny( IsChecked() ) );
1041 setLabel();
1044 void setLabel()
1046 SetText( String::CreateFromAscii( IsChecked() ? "true" : "false" ) );
1050 struct AnyListBox : public AnyWidget, layout::ListBox
1052 AnyListBox( Widget *pWidget, rtl::OUString aPropName,
1053 Widget::PropertyKind aPropKind, Window *pWinParent )
1054 : AnyWidget( pWidget, aPropName, aPropKind ), layout::ListBox( pWinParent, WB_DROPDOWN )
1056 SetSelectHdl( LINK( this, AnyWidget, ApplyPropertyHdl ) );
1059 virtual layout::Window *getWindow()
1060 { return this; }
1062 virtual void load()
1064 SelectEntryPos( sal::static_int_cast< USHORT >( getValue().toInt32() ) );
1065 checkProperty();
1068 virtual void store()
1070 save( uno::makeAny( (short) GetSelectEntryPos() ) );
1074 struct AnyAlign : public AnyListBox
1076 AnyAlign( Widget *pWidget, rtl::OUString aPropName,
1077 Widget::PropertyKind aPropKind, Window *pWinParent )
1078 : AnyListBox( pWidget, aPropName, aPropKind, pWinParent )
1080 InsertEntry( XubString::CreateFromAscii( "Left" ) );
1081 InsertEntry( XubString::CreateFromAscii( "Center" ) );
1082 InsertEntry( XubString::CreateFromAscii( "Right" ) );
1083 load();
1087 /* AnyListBox and AnyComboBox different in that a ComboBox allows the user
1088 to add other options, operating in strings, instead of constants.
1089 (its more like a suggestive AnyEdit) */
1090 struct AnyComboBox : public AnyWidget, layout::ComboBox
1092 AnyComboBox( Widget *pWidget, rtl::OUString aPropName,
1093 Widget::PropertyKind aPropKind, Window *pWinParent )
1094 : AnyWidget( pWidget, aPropName, aPropKind ), layout::ComboBox( pWinParent, WB_DROPDOWN )
1096 SetModifyHdl( LINK( this, AnyComboBox, ApplyPropertyHdl ) );
1099 virtual layout::Window *getWindow()
1100 { return this; }
1102 virtual void load()
1104 SetText( getValue() );
1105 checkProperty();
1108 virtual void store()
1110 save( uno::makeAny( (rtl::OUString) GetText() ) );
1114 struct AnyFontStyle : public AnyComboBox
1116 AnyFontStyle( Widget *pWidget, rtl::OUString aPropName,
1117 Widget::PropertyKind aPropKind, Window *pWinParent )
1118 : AnyComboBox( pWidget, aPropName, aPropKind, pWinParent )
1120 InsertEntry( XubString::CreateFromAscii( "Bold" ) );
1121 InsertEntry( XubString::CreateFromAscii( "Italic" ) );
1122 InsertEntry( XubString::CreateFromAscii( "Bold Italic" ) );
1123 InsertEntry( XubString::CreateFromAscii( "Fett" ) );
1124 load();
1128 layout::FixedText *mpLabel;
1129 layout::CheckBox *mpFlag;
1130 AnyWidget *mpValue;
1132 public:
1133 PropertyEntry( layout::Window *pWinParent, AnyWidget *pAnyWidget )
1135 mpLabel = new layout::FixedText( pWinParent );
1137 // append ':' to aPropName
1138 rtl::OUStringBuffer buf( pAnyWidget->maPropName );
1139 buf.append( sal_Unicode (':') );
1140 mpLabel->SetText( buf.makeStringAndClear() );
1142 mpValue = pAnyWidget;
1143 mpFlag = new layout::CheckBox( pWinParent );
1144 mpFlag->SetToggleHdl( LINK( mpValue, AnyWidget, FlagToggledHdl ) );
1145 mpValue->mpFlag = mpFlag;
1148 ~PropertyEntry()
1150 #if DEBUG_PRINT
1151 fprintf(stderr, "REMOVING label, flag and value\n");
1152 #endif
1153 delete mpLabel;
1154 delete mpFlag;
1155 delete mpValue;
1158 // Use this factory rather than the constructor -- check for NULL
1159 static PropertyEntry *construct( Widget *pWidget, rtl::OUString aPropName,
1160 Widget::PropertyKind aPropKind, sal_uInt16 nType,
1161 layout::Window *pWinParent )
1163 AnyWidget *pAnyWidget;
1164 switch (nType) {
1165 case uno::TypeClass_STRING:
1166 if ( aPropName.compareToAscii( "FontStyleName" ) == 0 )
1168 pAnyWidget = new AnyFontStyle( pWidget, aPropName, aPropKind, pWinParent );
1169 break;
1171 pAnyWidget = new AnyEdit( pWidget, aPropName, aPropKind, pWinParent );
1172 break;
1173 case uno::TypeClass_SHORT:
1174 if ( aPropName.compareToAscii( "Align" ) == 0 )
1176 pAnyWidget = new AnyAlign( pWidget, aPropName, aPropKind, pWinParent );
1177 break;
1179 // otherwise, treat as any other number...
1180 case uno::TypeClass_LONG:
1181 case uno::TypeClass_UNSIGNED_LONG:
1182 pAnyWidget = new AnyInteger( pWidget, aPropName, aPropKind, pWinParent );
1183 break;
1184 case uno::TypeClass_FLOAT:
1185 case uno::TypeClass_DOUBLE:
1186 pAnyWidget = new AnyFloat( pWidget, aPropName, aPropKind, pWinParent );
1187 break;
1188 case uno::TypeClass_BOOLEAN:
1189 pAnyWidget = new AnyCheckBox( pWidget, aPropName, aPropKind, pWinParent );
1190 break;
1191 default:
1192 return NULL;
1194 return new PropertyEntry( pWinParent, pAnyWidget );
1198 layout::Window *mpParentWindow;
1200 std::list< PropertyEntry* > maPropertiesList;
1201 layout::FixedLine *mpSeparator;
1203 // some properties are obscure, or simply don't make sense in this
1204 // context. Let's just ignore them.
1205 // Maybe we could offer them in an expander or something...
1206 static bool toIgnore( rtl::OUString prop )
1208 // binary search -- keep the list sorted alphabetically
1209 static char const *toIgnoreList[] = {
1210 "DefaultControl", "FocusOnClick", "FontCharWidth", "FontCharset",
1211 "FontEmphasisMark", "FontFamily", "FontHeight", "FontKerning", "FontName",
1212 "FontOrientation", "FontPitch", "FontRelief", "FontSlant", "FontStrikeout",
1213 "FontType", "FontWordLineMode", "HelpText", "HelpURL", "MultiLine",
1214 "Printable", "Repeat", "RepeatDelay", "Tabstop"
1217 #if 0
1218 // checks list sanity -- enable this when you add some entries...
1219 for ( unsigned int i = 1; i < sizeof( toIgnoreList )/sizeof( char * ); i++ )
1221 if ( strcmp(toIgnoreList[i-1], toIgnoreList[i]) >= 0 )
1223 printf("ignore list not ordered properly: "
1224 "'%s' should come before '%s'\n",
1225 toIgnoreList[i], toIgnoreList[i-1]);
1226 exit(-1);
1229 #endif
1231 int min = 0, max = sizeof( toIgnoreList )/sizeof( char * ) - 1, mid, cmp;
1232 do {
1233 mid = min + (max - min)/2;
1234 cmp = prop.compareToAscii( toIgnoreList[ mid ] );
1235 if ( cmp > 0 )
1236 min = mid+1;
1237 else if ( cmp < 0 )
1238 max = mid-1;
1239 else
1240 return true;
1241 } while ( min <= max );
1242 return false;
1245 public:
1246 PropertiesList( layout::Dialog *dialog )
1247 : layout::Table( dialog, "properties-box" )
1248 , mpParentWindow( dialog ), mpSeparator( 0 )
1252 ~PropertiesList()
1254 clear();
1257 private:
1258 // auxiliary, add properties from the peer to the list
1259 void addProperties( Widget *pWidget, Widget::PropertyKind rKind )
1261 Widget::PropertyIterator it( pWidget, rKind );
1262 while ( it.hasNext() )
1264 beans::Property prop = it.next();
1265 rtl::OUString name( prop.Name );
1266 if ( toIgnore( name ) )
1267 continue;
1268 sal_uInt16 type = static_cast< sal_uInt16 >( prop.Type.getTypeClass() );
1270 PropertyEntry *propEntry = PropertyEntry::construct(
1271 pWidget, name, rKind, type, mpParentWindow );
1273 if ( propEntry )
1275 Add( propEntry->mpLabel, false, false );
1277 // HACK: one of these will return Null...
1278 Add( propEntry->mpValue->getWindow(), true, false );
1279 Add( propEntry->mpValue->getContainer(), true, false );
1281 Add( propEntry->mpFlag, false, false );
1282 maPropertiesList.push_back( propEntry );
1287 public:
1288 void selectedWidget( Widget *pWidget )
1290 clear();
1292 if ( !pWidget )
1293 return;
1295 addProperties( pWidget, Widget::CONTAINER_PROPERTY );
1297 mpSeparator = new layout::FixedLine( mpParentWindow );
1298 // TODO: we may want to have to separate list widgets here...
1299 Add( mpSeparator, false, false, 3, 1 );
1301 addProperties( pWidget, Widget::WINDOW_PROPERTY );
1303 ShowAll( true );
1306 void clear()
1308 ///FIXME: crash
1309 Container::Clear();
1311 for ( std::list< PropertyEntry* >::iterator it = maPropertiesList.begin();
1312 it != maPropertiesList.end(); it++)
1313 delete *it;
1314 maPropertiesList.clear();
1316 delete mpSeparator;
1317 mpSeparator = NULL;
1321 IMPL_LINK( PropertiesList::PropertyEntry::AnyWidget, ApplyPropertyHdl, layout::Window *, pWin )
1323 (void) pWin;
1324 store();
1325 return 0;
1328 IMPL_LINK( PropertiesList::PropertyEntry::AnyWidget, FlagToggledHdl, layout::CheckBox *, pCheck )
1330 #if DEBUG_PRINT
1331 fprintf(stderr, "Property flag pressed -- is: %d\n", pCheck->IsChecked());
1332 #endif
1333 if ( !mbBlockFlagCallback )
1335 bool checked = pCheck->IsChecked();
1336 if ( !checked ) // revert
1338 #if DEBUG_PRINT
1339 fprintf(stderr, "revert\n");
1340 #endif
1341 load();
1343 else
1345 #if DEBUG_PRINT
1346 fprintf(stderr, "user can't dirty the flag!\n");
1347 #endif
1348 // User can't flag the property as dirty
1349 // Actually, we may want to allow the designer to force a property to be stored.
1350 // Could be useful when the default value of some new property wasn't yet decided...
1351 CheckFlag( false, true );
1354 #if DEBUG_PRINT
1355 else
1356 fprintf(stderr, "Property flag pressed -- BLOCKED\n");
1357 #endif
1358 return 0;
1361 IMPL_LINK( PropertiesList::PropertyEntry::AnyEdit, ExpandEditHdl, layout::PushButton *, pBtn )
1363 setAsMultiLine( pBtn->IsChecked() );
1364 return 0;
1367 //** SortListBox auxiliary widget
1369 class SortListBox
1370 { // For a manual sort ListBox; asks for a ListBox and Up/Down/Remove
1371 // buttons to wrap
1372 DECL_LINK( ItemSelectedHdl, layout::ListBox* );
1373 DECL_LINK( UpPressedHdl, layout::Button* );
1374 DECL_LINK( DownPressedHdl, layout::Button* );
1375 DECL_LINK( RemovePressedHdl, layout::Button* );
1376 layout::PushButton *mpUpButton, *mpDownButton, *mpRemoveButton;
1378 protected:
1379 layout::ListBox *mpListBox;
1381 virtual void upPressed( USHORT nPos )
1383 XubString str = mpListBox->GetSelectEntry();
1384 mpListBox->RemoveEntry( nPos );
1385 nPos = mpListBox->InsertEntry( str, nPos-1 );
1386 mpListBox->SelectEntryPos( nPos );
1389 virtual void downPressed( USHORT nPos )
1391 XubString str = mpListBox->GetSelectEntry();
1392 mpListBox->RemoveEntry( nPos );
1393 nPos = mpListBox->InsertEntry( str, nPos+1 );
1394 mpListBox->SelectEntryPos( nPos );
1397 virtual void removePressed( USHORT nPos )
1399 mpListBox->RemoveEntry( nPos );
1402 virtual void itemSelected( USHORT nPos )
1404 // if we had some XLayoutContainer::canAdd() or maxChildren() function
1405 // we could make a function to check if we can move selected and enable/
1406 // /disable the move buttons as appropriate
1408 if ( nPos == LISTBOX_ENTRY_NOTFOUND )
1410 mpUpButton->Disable();
1411 mpDownButton->Disable();
1412 mpRemoveButton->Disable();
1414 else
1416 mpUpButton->Enable();
1417 mpDownButton->Enable();
1418 mpRemoveButton->Enable();
1422 public:
1423 SortListBox( layout::ListBox *pListBox, layout::PushButton *pUpButton, layout::PushButton *pDownButton,
1424 layout::PushButton *pRemoveButton )
1425 : mpUpButton( pUpButton), mpDownButton( pDownButton), mpRemoveButton( pRemoveButton ),
1426 mpListBox( pListBox )
1428 mpListBox->SetSelectHdl( LINK( this, SortListBox, ItemSelectedHdl ) );
1430 mpUpButton->SetModeImage( layout::Image ( "res/commandimagelist/lc_moveup.png" ) );
1431 mpUpButton->SetImageAlign( IMAGEALIGN_LEFT );
1432 mpUpButton->SetClickHdl( LINK( this, SortListBox, UpPressedHdl ) );
1434 mpDownButton->SetModeImage( layout::Image ( "res/commandimagelist/lc_movedown.png" ) );
1435 mpDownButton->SetImageAlign( IMAGEALIGN_LEFT );
1436 mpDownButton->SetClickHdl( LINK( this, SortListBox, DownPressedHdl ) );
1438 // "res/commandimagelist/lch_delete.png", "res/commandimagelist/lc_delete.png"
1439 mpRemoveButton->SetModeImage( layout::Image ( "res/commandimagelist/sc_closedoc.png" ) );
1440 mpRemoveButton->SetImageAlign( IMAGEALIGN_LEFT );
1441 mpRemoveButton->SetClickHdl( LINK( this, SortListBox, RemovePressedHdl ) );
1443 // fire an un-select event
1444 itemSelected( LISTBOX_ENTRY_NOTFOUND );
1447 virtual ~SortListBox();
1450 SortListBox::~SortListBox()
1452 delete mpListBox;
1453 delete mpUpButton;
1454 delete mpDownButton;
1455 delete mpRemoveButton;
1458 IMPL_LINK( SortListBox, UpPressedHdl, layout::Button *, pBtn )
1460 (void) pBtn;
1461 USHORT pos = mpListBox->GetSelectEntryPos();
1462 if ( pos > 0 && pos != LISTBOX_ENTRY_NOTFOUND )
1463 upPressed( pos );
1464 return 0;
1467 IMPL_LINK( SortListBox, DownPressedHdl, layout::Button *, pBtn )
1469 (void) pBtn;
1470 USHORT pos = mpListBox->GetSelectEntryPos();
1471 if ( pos < mpListBox->GetEntryCount() && pos != LISTBOX_ENTRY_NOTFOUND )
1472 downPressed( pos );
1473 return 0;
1476 IMPL_LINK( SortListBox, RemovePressedHdl, layout::Button *, pBtn )
1478 (void) pBtn;
1479 USHORT pos = mpListBox->GetSelectEntryPos();
1480 if ( pos != LISTBOX_ENTRY_NOTFOUND )
1481 removePressed( pos );
1482 return 0;
1485 IMPL_LINK( SortListBox, ItemSelectedHdl, layout::ListBox *, pList )
1487 (void) pList;
1488 USHORT pos = mpListBox->GetSelectEntryPos();
1489 itemSelected( pos );
1490 return 0;
1493 //** LayoutTree widget
1495 class LayoutTree : public SortListBox
1497 public:
1498 struct Listener
1500 virtual void widgetSelected( Widget *pWidget ) = 0;
1503 private:
1504 Listener *mpListener;
1506 public:
1507 Widget *mpRootWidget;
1509 LayoutTree( layout::Dialog *dialog )
1510 : SortListBox( new layout::ListBox( dialog, "layout-tree" ),
1511 new layout::PushButton( dialog, "layout-up-button" ),
1512 new layout::PushButton( dialog, "layout-down-button" ),
1513 new layout::PushButton( dialog, "layout-remove-button" ) )
1515 layout::PeerHandle handle = dialog->GetPeerHandle( "preview-box" );
1516 uno::Reference< awt::XLayoutConstrains > xWidget( handle, uno::UNO_QUERY );
1517 mpRootWidget = new Widget( xWidget, "root" );
1520 virtual ~LayoutTree();
1522 Widget *getWidget( int nPos )
1524 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
1525 return FlatLayout::get( mpRootWidget, nPos );
1526 return NULL;
1529 Widget *getSelectedWidget()
1531 Widget *pWidget = getWidget( mpListBox->GetSelectEntryPos() );
1532 if ( !pWidget ) // return root, if none selected
1533 pWidget = mpRootWidget;
1534 return pWidget;
1537 void selectWidget( Widget *pWidget )
1539 int pos = FlatLayout::get( mpRootWidget, pWidget );
1540 if ( pos == -1 )
1541 // if asked to select hidden root, select visible root
1542 pos = 0;
1543 mpListBox->SelectEntryPos( sal::static_int_cast< USHORT >( pos ) );
1546 void rebuild()
1548 struct inner
1550 // pads a string with whitespaces
1551 static rtl::OUString padString( rtl::OUString name, int depth )
1553 rtl::OStringBuffer aBuf( depth * 4 + name.getLength() + 2 );
1554 for (int i = 0; i < depth; i++)
1555 aBuf.append( " " );
1556 aBuf.append( rtl::OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ) );
1557 return rtl::OUString( aBuf.getStr(), aBuf.getLength(),
1558 RTL_TEXTENCODING_UTF8 );
1562 mpListBox->Clear();
1563 for ( Widget *i = FlatLayout::next( mpRootWidget ); i; i = FlatLayout::next( i ) )
1564 mpListBox->InsertEntry( inner::padString( i->getLabel(), i->getDepth()-1 ) );
1566 // any selection, no longer is. ListBox doesn't fire the event on this case;
1567 // force it.
1568 itemSelected( LISTBOX_ENTRY_NOTFOUND );
1571 void setListener( Listener *pListener )
1572 { mpListener = pListener; }
1574 // print in XML format...
1576 static rtl::OUString toXMLNaming (const rtl::OUString &string)
1578 rtl::OUStringBuffer buffer (string.getLength());
1579 sal_Unicode *str = string.pData->buffer;
1580 for (int i = 0; i < string.getLength(); i++) {
1581 if ( str[i] >= 'A' && str[i] <= 'Z' )
1583 if ( i > 0 )
1584 buffer.append ((sal_Unicode) '-');
1585 buffer.append ((sal_Unicode) (str[i] - 'A' + 'a'));
1587 else
1588 buffer.append ((sal_Unicode) str[i]);
1591 return buffer.makeStringAndClear();
1594 void print()
1596 printf("\t\tExport:\n");
1597 printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1598 "<dialog xmlns=\"http://openoffice.org/2007/layout\"\n"
1599 " xmlns:cnt=\"http://openoffice.org/2007/layout/container\"\n"
1600 " id=\"dialog\" title=\"Unnamed\" sizeable=\"true\" >\n");
1602 for ( Widget *i = FlatLayout::next( mpRootWidget ); i; i = FlatLayout::next( i ) )
1604 for ( int d = i->getDepth(); d > 0; d-- )
1605 printf(" ");
1606 printf("<%s ", OUSTRING_CSTR( i->getUnoName() ) );
1608 for ( int kind = 0; kind < 2; kind++ )
1610 Widget::PropertyKind wKind = kind == 0 ? Widget::WINDOW_PROPERTY
1611 : Widget::CONTAINER_PROPERTY;
1612 Widget::PropertyIterator it( i, wKind );
1613 while ( it.hasNext() )
1615 beans::Property prop = it.next();
1616 if ( !i->isPropertyTouched( prop.Name, wKind ) )
1617 continue;
1619 rtl::OUString value = i->getProperty( prop.Name, wKind );
1620 if ( prop.Type.getTypeClass() == uno::TypeClass_BOOLEAN )
1622 if ( value.compareToAscii( "0" ) )
1623 value = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("false") );
1624 else
1625 value = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("true") );
1628 if ( value.getLength() > 0 )
1629 printf("%s%s=\"%s\" ",
1630 kind == 0 ? "" : "cnt:",
1631 OUSTRING_CSTR( toXMLNaming( prop.Name ) ), OUSTRING_CSTR( value )
1636 printf("/>\n");
1638 printf("</dialog>\n");
1641 protected:
1642 virtual void upPressed( USHORT nPos )
1644 Widget *pWidget = getWidget( nPos );
1645 if ( FlatLayout::moveWidget( pWidget, true ) )
1646 rebuild();
1647 selectWidget( pWidget );
1650 virtual void downPressed( USHORT nPos )
1652 Widget *pWidget = getWidget( nPos );
1653 if ( FlatLayout::moveWidget( pWidget, false ) )
1654 rebuild();
1655 selectWidget( pWidget );
1658 virtual void removePressed( USHORT nPos )
1660 Widget *pWidget = getWidget( nPos );
1661 if ( pWidget )
1663 pWidget->up()->removeChild( pWidget );
1664 delete pWidget;
1665 rebuild();
1669 virtual void itemSelected( USHORT nPos )
1671 mpListener->widgetSelected( getWidget( nPos ) );
1672 SortListBox::itemSelected( nPos );
1676 LayoutTree::~LayoutTree()
1678 delete mpRootWidget;
1681 //** EditorImpl
1683 class EditorImpl : public LayoutTree::Listener
1685 void createWidget( const char *unoName );
1687 PropertiesList *mpPropertiesList;
1688 LayoutTree *mpLayoutTree;
1690 layout::PushButton *pImportButton, *pExportButton;
1691 #ifdef FILEDLG
1692 FileDialog *pImportDialog;
1693 #endif
1694 DECL_LINK( ImportButtonHdl, layout::PushButton* );
1695 DECL_LINK( ExportButtonHdl, layout::PushButton* );
1696 #ifdef FILEDLG
1697 DECL_LINK( ImportDialogHdl, FileDialog* );
1698 #endif
1700 // framework stuff
1701 uno::Reference< lang::XMultiServiceFactory > mxFactory;
1702 uno::Reference< awt::XToolkit > mxToolkit;
1703 uno::Reference< awt::XWindow > mxToplevel;
1705 virtual void widgetSelected( Widget *pWidget );
1706 DECL_LINK( CreateWidgetHdl, layout::Button* );
1708 std::list< layout::PushButton *> maCreateButtons;
1710 public:
1712 EditorImpl( layout::Dialog *dialog,
1713 // we should probable open this channel (or whatever its called) ourselves
1714 uno::Reference< lang::XMultiServiceFactory > xMSF );
1715 virtual ~EditorImpl();
1717 void loadFile( const rtl::OUString &aTestFile );
1720 EditorImpl::EditorImpl( layout::Dialog *dialog,
1721 uno::Reference< lang::XMultiServiceFactory > xFactory )
1722 : mxFactory( xFactory )
1723 , mxToplevel( dialog->GetPeerHandle( "dialog" ), uno::UNO_QUERY )
1724 // FIXME: any of these should work
1725 //dialog->getContext()->getRoot(), uno::UNO_QUERY )
1726 // dialog->GetPeer(), uno::UNO_QUERY )
1728 #if DEBUG_PRINT
1729 fprintf (stderr, "EditorImpl()\n");
1730 #endif
1731 // framework
1732 mxToolkit = uno::Reference< awt::XToolkit >(
1733 mxFactory->createInstance(
1734 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.Toolkit" ) ) ),
1735 uno::UNO_QUERY );
1736 assert( mxToolkit.is() );
1738 // custom widgets
1739 #if DEBUG_PRINT
1740 fprintf (stderr, "custom widgets\n");
1741 #endif
1742 mpPropertiesList = new PropertiesList( dialog );
1744 mpLayoutTree = new LayoutTree( dialog );
1745 mpLayoutTree->setListener( this );
1747 /* if ( xImport.is() )
1748 mpLayoutTree->getWidget( -1 )->addChild( new Widget( xImport, "import" ) );*/
1750 // create buttons
1751 layout::Container aWidgets( dialog, "create-widget" );
1752 layout::Container aContainers( dialog, "create-container" );
1753 for ( int i = 0; i < WIDGETS_SPECS_LEN; i++ )
1755 layout::PushButton *pBtn = new layout::PushButton( (layout::Window *) dialog );
1756 pBtn->SetText( rtl::OUString::createFromAscii( WIDGETS_SPECS[ i ].pLabel ) );
1757 pBtn->SetClickHdl( LINK( this, EditorImpl, CreateWidgetHdl ) );
1758 if ( WIDGETS_SPECS[ i ].pIconName != NULL )
1760 rtl::OString aPath ("res/commandimagelist/");
1761 aPath += WIDGETS_SPECS[ i ].pIconName;
1762 layout::Image aImg( aPath );
1763 pBtn->SetModeImage( aImg );
1764 pBtn->SetImageAlign( IMAGEALIGN_LEFT );
1766 pBtn->Show();
1767 maCreateButtons.push_back( pBtn );
1768 layout::Container *pBox = WIDGETS_SPECS[ i ].bIsContainer ? &aContainers : &aWidgets;
1769 pBox->Add( pBtn );
1772 #ifdef FILEDLG
1773 fprintf(stderr,"creating file dialog\n");
1774 pImportDialog = new FileDialog( NULL/*(layout::Window *) dialog*/, 0 );
1775 fprintf(stderr,"connecting it\n");
1776 pImportDialog->SetFileSelectHdl( LINK( this, EditorImpl, ImportDialogHdl ) );
1777 fprintf(stderr,"done file dialog\n");
1778 #endif
1780 /* pImportButton = new layout::PushButton( dialog, "import-button" );
1781 pImportButton->SetClickHdl( LINK( this, EditorImpl, ImportButtonHdl ) );*/
1782 pExportButton = new layout::PushButton( dialog, "export-button" );
1783 pExportButton->SetClickHdl( LINK( this, EditorImpl, ExportButtonHdl ) );
1786 EditorImpl::~EditorImpl()
1788 delete mpPropertiesList;
1789 delete mpLayoutTree;
1790 for ( std::list< layout::PushButton * >::const_iterator i = maCreateButtons.begin();
1791 i != maCreateButtons.end(); i++)
1792 delete *i;
1793 delete pImportButton;
1794 delete pExportButton;
1795 #ifdef FILEDLG
1796 delete pImportDialog;
1797 #endif
1800 void EditorImpl::loadFile( const rtl::OUString &aTestFile )
1802 fprintf( stderr, "TEST: layout instance\n" );
1803 uno::Reference< awt::XLayoutRoot > xRoot
1804 ( new EditorRoot( mxFactory, mpLayoutTree->mpRootWidget ) );
1807 mxMSF->createInstance
1808 ( ::rtl::OUString::createFromAscii( "com.sun.star.awt.Layout" ) ),
1809 uno::UNO_QUERY );
1811 if ( !xRoot.is() )
1813 throw uno::RuntimeException(
1814 OUString( RTL_CONSTASCII_USTRINGPARAM("could not create awt Layout component!") ),
1815 uno::Reference< uno::XInterface >() );
1818 #if DEBUG_PRINT
1819 fprintf( stderr, "TEST: initing root\n" );
1820 #endif
1822 uno::Reference< lang::XInitialization > xInit( xRoot, uno::UNO_QUERY );
1823 if ( !xInit.is() )
1825 throw uno::RuntimeException(
1826 OUString( RTL_CONSTASCII_USTRINGPARAM("Layout has no XInitialization!") ),
1827 uno::Reference< uno::XInterface >() );
1830 #if DEBUG_PRINT
1831 fprintf( stderr, "TEST: running parser\n" );
1832 #endif
1833 uno::Sequence< uno::Any > aParams( 1 );
1834 aParams[0] <<= aTestFile;
1835 #if DEBUG_PRINT
1836 fprintf( stderr, "TEST: do it\n" );
1837 #endif
1838 xInit->initialize( aParams );
1839 #if DEBUG_PRINT
1840 fprintf( stderr, "TEST: file loaded\n" );
1841 #endif
1843 mpLayoutTree->rebuild();
1846 void EditorImpl::createWidget( const char *name )
1848 Widget *pWidget = mpLayoutTree->getSelectedWidget();
1850 Widget *pChild = new Widget( rtl::OUString(), mxToolkit, uno::Reference< awt::XLayoutContainer >( mxToplevel, uno::UNO_QUERY ), rtl::OUString::createFromAscii( name ), awt::WindowAttribute::SHOW );
1851 if ( !pWidget->addChild( pChild ) )
1853 delete pChild;
1854 // we may want to popup an error message
1856 else
1858 mpLayoutTree->rebuild();
1859 mpLayoutTree->selectWidget( pWidget );
1863 void EditorImpl::widgetSelected( Widget *pWidget )
1865 // we know can't add widget to a non-container, so let's disable the create
1866 // buttons then. Would be nice to have a method to check if a container is
1867 // full as well...
1868 if ( !pWidget || pWidget->isContainer() )
1870 for ( std::list< layout::PushButton *>::const_iterator it = maCreateButtons.begin();
1871 it != maCreateButtons.end(); it++)
1872 (*it)->Enable();
1874 else
1876 for ( std::list< layout::PushButton *>::const_iterator it = maCreateButtons.begin();
1877 it != maCreateButtons.end(); it++)
1878 (*it)->Disable();
1881 mpPropertiesList->selectedWidget( pWidget );
1884 IMPL_LINK( EditorImpl, CreateWidgetHdl, layout::Button *, pBtn )
1886 int i = 0;
1887 for ( std::list< layout::PushButton *>::const_iterator it = maCreateButtons.begin();
1888 it != maCreateButtons.end(); it++, i++ )
1890 if ( pBtn == *it )
1891 break;
1893 assert( i < WIDGETS_SPECS_LEN );
1894 createWidget( WIDGETS_SPECS[i].pName );
1895 return 0;
1898 IMPL_LINK( EditorImpl, ImportButtonHdl, layout::PushButton *, pBtn )
1900 (void) pBtn;
1901 #if DEBUG_PRINT
1902 fprintf(stderr, "IMPORT!\n");
1903 #endif
1904 #ifdef FILEDLG
1905 pImportDialog->Execute();
1906 #endif
1908 return 0;
1911 #ifdef FILEDLG
1912 IMPL_LINK( EditorImpl, ImportDialogHdl, FileDialog *, pDialog )
1914 UniString path = pDialog->GetPath();
1915 //fprintf(stderr, "Executing import dialog!\n");
1917 #if DEBUG_PRINT
1918 fprintf(stderr, "got import file: %s\n",rtl::OUStringToOString( path, RTL_TEXTENCODING_ASCII_US ).getStr() );
1919 #endif
1921 return 0;
1923 #endif
1925 IMPL_LINK( EditorImpl, ExportButtonHdl, layout::PushButton *, pBtn )
1927 (void) pBtn;
1928 mpLayoutTree->print();
1929 return 0;
1932 //** Editor, the Dialog
1934 Editor::Editor( uno::Reference< lang::XMultiServiceFactory > xFactory,
1935 rtl::OUString aFile )
1936 : layout::Dialog( (Window*) (NULL), "editor.xml", "dialog" )
1937 , mpImpl( new EditorImpl( this, xFactory ) )
1939 if ( aFile.getLength() )
1940 mpImpl->loadFile( aFile );
1942 // parent:
1943 FreeResource();
1946 Editor::~Editor()
1948 delete mpImpl;