1877 lines
60 KiB
C++
1877 lines
60 KiB
C++
![]() |
#include "editor.hxx"
|
||
|
|
||
|
#undef NDEBUG
|
||
|
#include <assert.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#include <vector>
|
||
|
#include <list>
|
||
|
#include <rtl/strbuf.hxx>
|
||
|
#include <rtl/ustrbuf.hxx>
|
||
|
|
||
|
using namespace layout::css;
|
||
|
|
||
|
using rtl::OUString;
|
||
|
|
||
|
#include <com/sun/star/awt/XWindow.hpp>
|
||
|
#include <com/sun/star/awt/XWindowPeer.hpp>
|
||
|
#include <com/sun/star/awt/XVclWindowPeer.hpp>
|
||
|
#include <com/sun/star/awt/XLayoutConstrains.hpp>
|
||
|
#include <com/sun/star/awt/XLayoutContainer.hpp>
|
||
|
#include <com/sun/star/awt/WindowAttribute.hpp>
|
||
|
|
||
|
#include <com/sun/star/awt/XToolkit.hpp>
|
||
|
#include <toolkit/helper/property.hxx>
|
||
|
|
||
|
#include <vcl/lstbox.h>
|
||
|
|
||
|
// FIXME:
|
||
|
//#define FILEDLG
|
||
|
|
||
|
// somewhat of a hack unfortunately ...
|
||
|
#include "layoutcore.hxx"
|
||
|
#include "root.hxx"
|
||
|
#include "helper.hxx"
|
||
|
|
||
|
//** Utilities
|
||
|
|
||
|
#define OUSTRING_CSTR( str ) \
|
||
|
rtl::OUStringToOString( str, RTL_TEXTENCODING_ASCII_US ).getStr()
|
||
|
|
||
|
// TODO: automatically generated
|
||
|
struct WidgetSpec {
|
||
|
const char *pLabel, *pName, *pIconName;
|
||
|
bool bIsContainer; };
|
||
|
static const WidgetSpec WIDGETS_SPECS[] = {
|
||
|
{ "Label", "fixedtext" , "sc_label.png", false },
|
||
|
{ "Button", "pushbutton" , "sc_pushbutton.png", false },
|
||
|
{ "Radio Button", "radiobutton" , "sc_radiobutton.png", false },
|
||
|
{ "Check Box", "checkbox" , "sc_checkbox.png", false },
|
||
|
{ "Line Edit", "edit" , "sc_edit.png", false },
|
||
|
{ "Numeric Field", "numericfield", "sc_numericfield.png", false },
|
||
|
{ "List Box ", "listbox" , NULL, false },
|
||
|
// containers
|
||
|
{ "Hor Box", "hbox" , NULL, true },
|
||
|
{ "Ver Box", "vbox" , NULL, true },
|
||
|
{ "Table", "table" , NULL, true },
|
||
|
{ "Alignment", "align" , NULL, true },
|
||
|
{ "Tab Control", "tabcontrol" , NULL, true },
|
||
|
{ "Hor Splitter", "hsplitter" , NULL, true },
|
||
|
{ "Ver Splitter", "vsplitter" , NULL, true },
|
||
|
{ "Scroller", "scroller" , NULL, true },
|
||
|
};
|
||
|
const int WIDGETS_SPECS_LEN = sizeof (WIDGETS_SPECS) / sizeof (WidgetSpec);
|
||
|
|
||
|
// TEMP: from helper
|
||
|
namespace layoutimpl {
|
||
|
|
||
|
typedef std::list< std::pair< rtl::OUString, rtl::OUString > > PropList;
|
||
|
|
||
|
css::uno::Reference< css::awt::XLayoutConstrains >
|
||
|
createWidget( css::uno::Reference< css::awt::XToolkit > xToolkit,
|
||
|
css::uno::Reference< css::uno::XInterface > xParent,
|
||
|
const rtl::OUString &rName, long nProps, bool bToplevel );
|
||
|
|
||
|
uno::Any anyFromString (const rtl::OUString &value, const uno::Type &type);
|
||
|
};
|
||
|
|
||
|
using namespace layout;
|
||
|
using namespace layoutimpl;
|
||
|
namespace css = ::com::sun::star;
|
||
|
|
||
|
static rtl::OUString anyToString (uno::Any value)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
switch (value.getValueTypeClass()) {
|
||
|
case uno::TypeClass_STRING:
|
||
|
return value.get<rtl::OUString>();
|
||
|
case uno::TypeClass_CONSTANT:
|
||
|
return rtl::OUString::valueOf (value.get<sal_Int32>());
|
||
|
case uno::TypeClass_LONG:
|
||
|
return rtl::OUString::valueOf (value.get<sal_Int64>());
|
||
|
case uno::TypeClass_SHORT:
|
||
|
// FIXME: seems broken
|
||
|
return rtl::OUString::valueOf ((sal_Int32) value.get<short>());
|
||
|
|
||
|
case uno::TypeClass_FLOAT:
|
||
|
return rtl::OUString::valueOf (value.get<float>());
|
||
|
case uno::TypeClass_DOUBLE:
|
||
|
return rtl::OUString::valueOf (value.get<double>());
|
||
|
|
||
|
case uno::TypeClass_BOOLEAN:
|
||
|
{
|
||
|
bool val = value.get<sal_Bool>();
|
||
|
return rtl::OUString( val ? "1" : "0", 1, RTL_TEXTENCODING_ASCII_US );
|
||
|
/* if ( val )
|
||
|
return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "true" ) );
|
||
|
else
|
||
|
return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "false" ) );*/
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
catch(...) {}
|
||
|
return rtl::OUString();
|
||
|
}
|
||
|
|
||
|
static inline long anyToNatural (uno::Any value)
|
||
|
{ return anyToString( value ).toInt64(); }
|
||
|
static inline double anyToDecimal (uno::Any value)
|
||
|
{ return anyToString( value ).toDouble(); }
|
||
|
|
||
|
/* XLayoutContainer/XLayoutConstrains are a bit of a hasle to work with.
|
||
|
Let's wrap them. */
|
||
|
class Widget : public layoutimpl::LayoutWidget {
|
||
|
friend class EditorRoot;
|
||
|
|
||
|
Widget *mpParent;
|
||
|
std::vector< Widget *> maChildren;
|
||
|
bool mbForeign;
|
||
|
|
||
|
rtl::OUString mrId;
|
||
|
rtl::OUString mrLabel, mrUnoName;
|
||
|
|
||
|
// TODO: store original properties. And some property handling methods.
|
||
|
long mnOriAttrbs;
|
||
|
layoutimpl::PropList maOriProps, maOriChildProps;
|
||
|
|
||
|
public:
|
||
|
|
||
|
// to be used to wrap the root
|
||
|
Widget( uno::Reference< awt::XLayoutConstrains > xImport, const char *label )
|
||
|
: mpParent( 0 ), mbForeign( true )
|
||
|
{
|
||
|
mxWidget = xImport;
|
||
|
mxContainer = uno::Reference< awt::XLayoutContainer >( mxWidget, uno::UNO_QUERY );
|
||
|
|
||
|
mrLabel = rtl::OUString( label, strlen( label ), RTL_TEXTENCODING_UTF8 );
|
||
|
|
||
|
#if 0 /* obsolete */
|
||
|
// FIXME: this code is meant to import a XML file. Just use the importer,
|
||
|
// then pass the root widget. But information like the ID string is lost.
|
||
|
// So, this needs to be more closely tight to the importer.
|
||
|
uno::Sequence< uno::Reference< awt::XLayoutConstrains > > aChildren;
|
||
|
for ( int i = 0; i < aChildren.getLength(); i++ )
|
||
|
{
|
||
|
Widget *pChild = new Widget( aChildren[ i ], "---" );
|
||
|
maChildren.push_back( pChild );
|
||
|
pChild->mpParent = this;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
Widget( rtl::OUString id, uno::Reference< awt::XToolkit > xToolkit,
|
||
|
uno::Reference< awt::XLayoutContainer > xParent,
|
||
|
rtl::OUString unoName, long nAttrbs )
|
||
|
: mpParent( 0 ), mbForeign( false ), mrId( id ),
|
||
|
mnOriAttrbs( nAttrbs )
|
||
|
{
|
||
|
while ( xParent.is() && !uno::Reference< awt::XWindow >( xParent, uno::UNO_QUERY ).is() )
|
||
|
{
|
||
|
uno::Reference< awt::XLayoutContainer > xContainer( xParent, uno::UNO_QUERY );
|
||
|
assert( xContainer.is() );
|
||
|
xParent = uno::Reference< awt::XLayoutContainer >( xContainer->getParent(), uno::UNO_QUERY );
|
||
|
}
|
||
|
|
||
|
mxWidget = layoutimpl::createWidget( xToolkit, xParent, unoName, nAttrbs );
|
||
|
assert( mxWidget.is() );
|
||
|
mxContainer = uno::Reference< awt::XLayoutContainer >( mxWidget, uno::UNO_QUERY );
|
||
|
|
||
|
mrLabel = mrUnoName = unoName;
|
||
|
// try to get a nicer label for the widget
|
||
|
for ( int i = 0; i < WIDGETS_SPECS_LEN; i++ )
|
||
|
if ( unoName.equalsAscii( WIDGETS_SPECS[ i ].pName ) )
|
||
|
{
|
||
|
const char *label = WIDGETS_SPECS[ i ].pLabel;
|
||
|
mrLabel = rtl::OUString( label, strlen( label ), RTL_TEXTENCODING_UTF8 );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// set default Text property
|
||
|
// TODO: disable editing of text fields, check boxes selected, etc...
|
||
|
#if 0
|
||
|
uno::Reference< awt::XVclWindowPeer> xVclPeer( mxWidget, uno::UNO_QUERY )
|
||
|
if ( xVclPeer.is() ) // XVclWindowPeer ignores missing / incorrect properties
|
||
|
|
||
|
//FIXME: it looks odd on widgets like NumericField seeing text which is deleted
|
||
|
// when you interact with it... We can avoid it for those widgets, by doing a getProp
|
||
|
// of "Text" and check if it is empty or not.
|
||
|
|
||
|
xVclPeer->setProperty( rtl::OUString::createFromAscii( "Text" ),
|
||
|
uno::makeAny( rtl::OUString::createFromAscii( "new widget" ) ) );
|
||
|
#endif
|
||
|
|
||
|
// store original properties
|
||
|
{
|
||
|
PropertyIterator it( this, WINDOW_PROPERTY );
|
||
|
while ( it.hasNext() )
|
||
|
{
|
||
|
beans::Property prop = it.next();
|
||
|
rtl::OUString name( prop.Name );
|
||
|
rtl::OUString value( getProperty( name, WINDOW_PROPERTY ) );
|
||
|
fprintf(stderr, "original property: %s = %s\n", OUSTRING_CSTR(name), OUSTRING_CSTR(value));
|
||
|
std::pair< rtl::OUString, rtl::OUString > pair( name, value );
|
||
|
maOriProps.push_back( pair );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
~Widget()
|
||
|
{
|
||
|
for ( std::vector< Widget *>::const_iterator it = maChildren.begin();
|
||
|
it != maChildren.end(); it++ )
|
||
|
delete *it;
|
||
|
if ( !mbForeign )
|
||
|
{
|
||
|
uno::Reference< lang::XComponent > xComp( mxWidget, uno::UNO_QUERY );
|
||
|
if ( xComp.is() )
|
||
|
// some widgets, like our containers, don't implement this interface...
|
||
|
xComp->dispose();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uno::Reference< awt::XLayoutConstrains > impl()
|
||
|
{
|
||
|
return mxWidget;
|
||
|
}
|
||
|
|
||
|
// LayoutWidget
|
||
|
virtual bool addChild( LayoutWidget *pChild )
|
||
|
{
|
||
|
return addChild( static_cast< Widget * >( pChild ) );
|
||
|
}
|
||
|
|
||
|
virtual void setProperties( const PropList &rProps )
|
||
|
{
|
||
|
// maOriProps = rProps;
|
||
|
LayoutWidget::setProperties( rProps );
|
||
|
}
|
||
|
|
||
|
virtual void setChildProperties( LayoutWidget *pChild, const PropList &rProps )
|
||
|
{
|
||
|
maOriChildProps = rProps;
|
||
|
LayoutWidget::setChildProperties( pChild, rProps );
|
||
|
}
|
||
|
|
||
|
// tree travel
|
||
|
Widget *up()
|
||
|
{
|
||
|
return mpParent;
|
||
|
}
|
||
|
|
||
|
Widget *down()
|
||
|
{
|
||
|
if ( maChildren.empty() )
|
||
|
return NULL;
|
||
|
return maChildren.front();
|
||
|
}
|
||
|
|
||
|
Widget *next()
|
||
|
{
|
||
|
if ( mpParent )
|
||
|
{
|
||
|
int pos = mpParent->getChildPos( this );
|
||
|
return mpParent->getChild( pos+1 );
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
Widget *prev()
|
||
|
{
|
||
|
if ( mpParent )
|
||
|
{
|
||
|
int pos = mpParent->getChildPos( this );
|
||
|
return mpParent->getChild( pos-1 );
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// handle
|
||
|
bool addChild( Widget *pChild, int pos = 0xffff )
|
||
|
{
|
||
|
if ( !mxContainer.is() )
|
||
|
return false;
|
||
|
|
||
|
uno::Sequence< uno::Reference < awt::XLayoutConstrains > > aChildren;
|
||
|
aChildren = mxContainer->getChildren();
|
||
|
int nChildrenLen = aChildren.getLength();
|
||
|
|
||
|
// ugly, but let's check if the container is next to full...
|
||
|
try {
|
||
|
mxContainer->addChild( pChild->mxWidget );
|
||
|
}
|
||
|
catch( awt::MaxChildrenException ex ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( pos < nChildrenLen )
|
||
|
{ // if its on the middle, we need to make space for it
|
||
|
mxContainer->removeChild( pChild->mxWidget );
|
||
|
for ( int i = pos; i < nChildrenLen; i++ )
|
||
|
mxContainer->removeChild( aChildren[ i ] );
|
||
|
mxContainer->addChild( pChild->mxWidget );
|
||
|
for ( int i = pos; i < nChildrenLen; i++ )
|
||
|
mxContainer->addChild( aChildren[ i ] );
|
||
|
maChildren.insert( maChildren.begin()+pos, pChild );
|
||
|
}
|
||
|
else
|
||
|
maChildren.push_back( pChild );
|
||
|
|
||
|
assert( pChild->mpParent == NULL );
|
||
|
pChild->mpParent = this;
|
||
|
|
||
|
// store container props
|
||
|
{
|
||
|
pChild->maOriChildProps.clear();
|
||
|
PropertyIterator it( pChild, CONTAINER_PROPERTY );
|
||
|
while ( it.hasNext() )
|
||
|
{
|
||
|
beans::Property prop = it.next();
|
||
|
rtl::OUString name( prop.Name );
|
||
|
rtl::OUString value( pChild->getProperty( name, CONTAINER_PROPERTY ) );
|
||
|
std::pair< rtl::OUString, rtl::OUString > pair( name, value );
|
||
|
pChild->maOriChildProps.push_back( pair );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool removeChild( Widget *pChild )
|
||
|
{
|
||
|
if ( !mxContainer.is() || pChild->mpParent != this )
|
||
|
return false;
|
||
|
|
||
|
mxContainer->removeChild( pChild->mxWidget );
|
||
|
|
||
|
unsigned int pos = getChildPos( pChild );
|
||
|
if ( pos < maChildren.size() )
|
||
|
maChildren.erase( maChildren.begin()+pos );
|
||
|
pChild->mpParent = NULL;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool swapWithChild( Widget *pChild )
|
||
|
{
|
||
|
if ( !pChild->isContainer() )
|
||
|
return false;
|
||
|
|
||
|
// remove all child's childrens, and try to add them here
|
||
|
removeChild( pChild );
|
||
|
|
||
|
// keep a copy for failure
|
||
|
std::vector< Widget *> aChildren = maChildren;
|
||
|
std::vector< Widget *> aChildChildren = pChild->maChildren;
|
||
|
|
||
|
for ( std::vector< Widget *>::const_iterator it = aChildChildren.begin();
|
||
|
it != aChildChildren.end(); it++ )
|
||
|
pChild->removeChild( *it );
|
||
|
|
||
|
for ( std::vector< Widget *>::const_iterator it = aChildChildren.begin();
|
||
|
it != aChildChildren.end(); it++ )
|
||
|
if ( !addChild( *it ) )
|
||
|
{ // failure
|
||
|
for ( std::vector< Widget *>::const_iterator jt = aChildChildren.begin();
|
||
|
jt != it; jt++ )
|
||
|
removeChild( *jt );
|
||
|
for ( std::vector< Widget *>::const_iterator jt = aChildChildren.begin();
|
||
|
jt != aChildChildren.end(); jt++ )
|
||
|
pChild->addChild( *jt );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Widget *pParent = up();
|
||
|
|
||
|
if ( pParent )
|
||
|
{
|
||
|
pParent->removeChild( this );
|
||
|
pParent->addChild( pChild );
|
||
|
}
|
||
|
pChild->addChild( this );
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
unsigned int getChildPos( Widget *pChild )
|
||
|
{
|
||
|
int i = 0;
|
||
|
for ( std::vector< Widget *>::const_iterator it = maChildren.begin();
|
||
|
it != maChildren.end(); it++, i++ )
|
||
|
if ( *it == pChild )
|
||
|
break;
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
Widget *getChild( int pos )
|
||
|
{
|
||
|
if ( pos >= 0 && pos < (signed) maChildren.size() )
|
||
|
return *(maChildren.begin() + pos);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
bool isContainer()
|
||
|
{ return mxContainer.is(); }
|
||
|
unsigned int getChildrenLen()
|
||
|
{ return maChildren.size(); }
|
||
|
|
||
|
rtl::OUString getLabel() const
|
||
|
{ return mrLabel; }
|
||
|
rtl::OUString getUnoName() const
|
||
|
{ return mrUnoName; }
|
||
|
|
||
|
int getDepth()
|
||
|
{
|
||
|
int depth = 0;
|
||
|
for ( Widget *pWidget = mpParent; pWidget; pWidget = pWidget->mpParent )
|
||
|
depth++;
|
||
|
return depth;
|
||
|
}
|
||
|
|
||
|
enum PropertyKind {
|
||
|
WINDOW_PROPERTY, CONTAINER_PROPERTY, WINBITS_PROPERTY
|
||
|
};
|
||
|
|
||
|
static rtl::OUString findProperty( const PropList &props, rtl::OUString propName )
|
||
|
{
|
||
|
for ( PropList::const_iterator it = props.begin(); it != props.end(); it++ )
|
||
|
if ( it->first.equalsIgnoreAsciiCase( propName ) )
|
||
|
return it->second;
|
||
|
fprintf(stderr, "Serious error: property '%s' not found\n", OUSTRING_CSTR(propName));
|
||
|
return rtl::OUString();
|
||
|
}
|
||
|
|
||
|
rtl::OUString getOriginalProperty( rtl::OUString rPropName, PropertyKind rKind )
|
||
|
{
|
||
|
rtl::OUString rValue;
|
||
|
switch ( rKind ) {
|
||
|
case WINDOW_PROPERTY:
|
||
|
rValue = findProperty( maOriProps, rPropName );
|
||
|
break;
|
||
|
case CONTAINER_PROPERTY:
|
||
|
rValue = findProperty( maOriChildProps, rPropName );
|
||
|
break;
|
||
|
case WINBITS_PROPERTY:
|
||
|
// TODO
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return rValue;
|
||
|
}
|
||
|
|
||
|
rtl::OUString getProperty( rtl::OUString rPropName, PropertyKind rKind )
|
||
|
{
|
||
|
rtl::OUString rValue;
|
||
|
switch ( rKind ) {
|
||
|
case WINDOW_PROPERTY:
|
||
|
rValue = anyToString( layoutimpl::prophlp::getProperty( mxWidget, rPropName ) );
|
||
|
break;
|
||
|
case CONTAINER_PROPERTY:
|
||
|
if ( mpParent )
|
||
|
rValue = anyToString( layoutimpl::prophlp::getProperty(
|
||
|
mpParent->mxContainer->getChildProperties( mxWidget ), rPropName ) );
|
||
|
break;
|
||
|
case WINBITS_PROPERTY:
|
||
|
// TODO
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return rValue;
|
||
|
}
|
||
|
|
||
|
bool isPropertyTouched( rtl::OUString propName, PropertyKind rKind )
|
||
|
{
|
||
|
rtl::OUString oriValue = getOriginalProperty( propName, rKind );
|
||
|
rtl::OUString newValue = getProperty( propName, rKind );
|
||
|
bool isTouched = oriValue != newValue;
|
||
|
fprintf(stderr, "is property '%s' touched? %s (%s vs %s)\n", OUSTRING_CSTR(propName), isTouched ? "yes" : "no", OUSTRING_CSTR(oriValue), OUSTRING_CSTR(newValue));
|
||
|
return isTouched;
|
||
|
}
|
||
|
|
||
|
void setProperty( rtl::OUString rPropName, PropertyKind rKind, uno::Any rValue )
|
||
|
{
|
||
|
switch ( rKind ) {
|
||
|
case WINDOW_PROPERTY:
|
||
|
layoutimpl::prophlp::setProperty( mxWidget, rPropName, rValue );
|
||
|
break;
|
||
|
case CONTAINER_PROPERTY:
|
||
|
if ( mpParent )
|
||
|
layoutimpl::prophlp::setProperty(
|
||
|
mpParent->mxContainer->getChildProperties( mxWidget ), rPropName, rValue );
|
||
|
break;
|
||
|
case WINBITS_PROPERTY:
|
||
|
// TODO
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct PropertyIterator {
|
||
|
friend class Widget;
|
||
|
PropertyKind mrKind;
|
||
|
uno::Sequence< beans::Property > maProps;
|
||
|
int nPropIt;
|
||
|
|
||
|
PropertyIterator( Widget *pWidget, PropertyKind rKind )
|
||
|
: mrKind( rKind ), nPropIt( 0 )
|
||
|
{
|
||
|
switch ( rKind )
|
||
|
{
|
||
|
case WINDOW_PROPERTY:
|
||
|
if ( layoutimpl::prophlp::canHandleProps( pWidget->mxWidget ) )
|
||
|
{
|
||
|
uno::Reference< beans::XPropertySetInfo > xInfo
|
||
|
= layoutimpl::prophlp::queryPropertyInfo( pWidget->mxWidget );
|
||
|
if ( !xInfo.is() )
|
||
|
return;
|
||
|
|
||
|
maProps = xInfo->getProperties();
|
||
|
}
|
||
|
break;
|
||
|
case CONTAINER_PROPERTY:
|
||
|
if ( pWidget->mpParent )
|
||
|
{
|
||
|
uno::Reference< beans::XPropertySet >xParentSet(
|
||
|
pWidget->mpParent->mxContainer->getChildProperties( pWidget->mxWidget ) );
|
||
|
if ( xParentSet.is())
|
||
|
{
|
||
|
uno::Reference< beans::XPropertySetInfo > xInfo( xParentSet->getPropertySetInfo() );
|
||
|
if ( xInfo.is() )
|
||
|
maProps = xInfo->getProperties();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case WINBITS_PROPERTY:
|
||
|
// TODO
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool hasNext()
|
||
|
{
|
||
|
return nPropIt < maProps.getLength();
|
||
|
}
|
||
|
|
||
|
beans::Property next()
|
||
|
{
|
||
|
/* rtl::OUString propName, propValue;
|
||
|
propName = maProps[ nPropIt ];
|
||
|
propValue = getProperty( propName, mrKind, false);
|
||
|
nPropIt++;
|
||
|
return std::pair< rtl::OUString, rtl::OUString > propPair( propName, propValue );*/
|
||
|
return maProps[ nPropIt++ ];
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
|
||
|
class EditorRoot : public layoutimpl::LayoutRoot {
|
||
|
Widget *mpParent;
|
||
|
|
||
|
public:
|
||
|
EditorRoot( const uno::Reference< lang::XMultiServiceFactory >& xFactory,
|
||
|
Widget *pParent )
|
||
|
: layoutimpl::LayoutRoot( xFactory ), mpParent( pParent )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// generation
|
||
|
virtual layoutimpl::LayoutWidget *create( rtl::OUString id, const rtl::OUString unoName,
|
||
|
long attrbs, uno::Reference< awt::XLayoutContainer > xParent )
|
||
|
{
|
||
|
if ( unoName.compareToAscii( "dialog" ) == 0 )
|
||
|
return mpParent;
|
||
|
|
||
|
// TODO: go through specs to map unoName to a more human-readable label
|
||
|
Widget *pWidget = new Widget( id, mxToolkit, xParent, unoName, attrbs );
|
||
|
if ( !mxWindow.is() )
|
||
|
mxWindow = uno::Reference< awt::XWindow >( pWidget->getPeer(), uno::UNO_QUERY );
|
||
|
|
||
|
if ( pWidget->mxContainer.is() )
|
||
|
pWidget->mxContainer->setLayoutUnit( mpParent->mxContainer->getLayoutUnit() );
|
||
|
|
||
|
return pWidget;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/* Working with the layout in 1D, as if it was a flat list. */
|
||
|
namespace FlatLayout
|
||
|
{
|
||
|
Widget *next( Widget *pWidget )
|
||
|
{
|
||
|
Widget *pNext;
|
||
|
pNext = pWidget->down();
|
||
|
if ( pNext ) return pNext;
|
||
|
pNext = pWidget->next();
|
||
|
if ( pNext ) return pNext;
|
||
|
for ( Widget *pUp = pWidget->up(); pUp != NULL; pUp = pUp->up() )
|
||
|
if ( (pNext = pUp->next()) != NULL )
|
||
|
return pNext;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Widget *prev( Widget *pWidget )
|
||
|
{
|
||
|
Widget *pPrev;
|
||
|
pPrev = pWidget->prev();
|
||
|
if ( !pPrev )
|
||
|
return pWidget->up();
|
||
|
|
||
|
Widget *pBottom = pPrev->down();
|
||
|
if ( pBottom )
|
||
|
{
|
||
|
while ( pBottom->down() || pBottom->next() )
|
||
|
{
|
||
|
for ( Widget *pNext = pBottom->next(); pNext; pNext = pNext->next() )
|
||
|
pBottom = pNext;
|
||
|
Widget *pDown = pBottom->down();
|
||
|
if ( pDown )
|
||
|
pBottom = pDown;
|
||
|
}
|
||
|
return pBottom;
|
||
|
}
|
||
|
return pPrev;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
bool moveWidget( Widget *pWidget, bool up /*or down*/ )
|
||
|
{
|
||
|
// Keep child parent&pos for in case of failure
|
||
|
Widget *pOriContainer = pWidget->up();
|
||
|
unsigned int oriChildPos = pOriContainer->getChildPos( pWidget );
|
||
|
|
||
|
// Get parent&sibling before removing it, since relations get cut
|
||
|
Widget *pSibling = up ? pWidget->prev() : pWidget->next();
|
||
|
Widget *pContainer = pWidget->up();
|
||
|
if ( !pContainer )
|
||
|
return false;
|
||
|
|
||
|
// try to swap with parent or child
|
||
|
// We need to allow for this at least for the root node...
|
||
|
if ( !pSibling )
|
||
|
{
|
||
|
if ( up )
|
||
|
{
|
||
|
if ( pContainer->swapWithChild( pWidget ) )
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// TODO: this is a nice feature, but we probably want to do it explicitely...
|
||
|
#if 0
|
||
|
if ( pWidget->down() && pWidget->swapWithChild( pWidget->down() ) )
|
||
|
return true;
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pContainer->removeChild( pWidget );
|
||
|
|
||
|
// if has up sibling -- append to it, else swap with it
|
||
|
if ( pSibling )
|
||
|
{
|
||
|
if ( pSibling->addChild( pWidget, up ? 0xffff : 0 ) )
|
||
|
return true;
|
||
|
|
||
|
unsigned int childPos = pContainer->getChildPos( pSibling );
|
||
|
if ( pContainer->addChild( pWidget, childPos + (up ? 0 : 1) ) )
|
||
|
return true; // should always be succesful
|
||
|
}
|
||
|
// go through parents -- try to get prepended to them
|
||
|
else
|
||
|
{
|
||
|
for ( ; pContainer && pContainer->up(); pContainer = pContainer->up() )
|
||
|
{
|
||
|
unsigned int childPos = pContainer->up()->getChildPos( pContainer );
|
||
|
if ( pContainer->up()->addChild( pWidget, childPos + (up ? 0 : 1) ) )
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// failed -- try to get it to its old position
|
||
|
if ( !pOriContainer->addChild( pWidget, oriChildPos ) )
|
||
|
{
|
||
|
// a parent should never reject a child back. but if it ever
|
||
|
// happens, just kill it, we don't run an orphanate here ;P
|
||
|
delete pWidget;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// NOTE: root is considered to be number -1
|
||
|
Widget *get( Widget *pRoot, int nb )
|
||
|
{
|
||
|
Widget *it;
|
||
|
for ( it = pRoot; it != NULL && nb >= 0; it = next( it ) )
|
||
|
nb--;
|
||
|
return it;
|
||
|
}
|
||
|
|
||
|
int get( Widget *pRoot, Widget *pWidget )
|
||
|
{
|
||
|
int nRet = -1;
|
||
|
Widget *it;
|
||
|
for ( it = pRoot; it != NULL && it != pWidget; it = next( it ) )
|
||
|
nRet++;
|
||
|
return nRet;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//** PropertiesList widget
|
||
|
|
||
|
class PropertiesList : public layout::Table
|
||
|
{
|
||
|
class PropertyEntry
|
||
|
{
|
||
|
friend class PropertiesList;
|
||
|
|
||
|
/* wrapper between the widget and Any */
|
||
|
struct AnyWidget
|
||
|
{
|
||
|
DECL_LINK( ApplyPropertyHdl, layout::Window* );
|
||
|
DECL_LINK( FlagToggledHdl, layout::CheckBox* );
|
||
|
|
||
|
AnyWidget( Widget *pWidget, rtl::OUString aPropName, Widget::PropertyKind aPropKind )
|
||
|
: mpWidget( pWidget ), maPropName( aPropName ), maPropKind( aPropKind )
|
||
|
{
|
||
|
mpFlag = 0;
|
||
|
mbBlockFlagCallback = false;
|
||
|
bFirstGet = true;
|
||
|
}
|
||
|
|
||
|
virtual ~AnyWidget()
|
||
|
{
|
||
|
fprintf(stderr, "~AnyWidget\n");
|
||
|
}
|
||
|
|
||
|
void save( uno::Any aValue )
|
||
|
{
|
||
|
mpWidget->setProperty( maPropName, maPropKind, aValue );
|
||
|
checkProperty();
|
||
|
}
|
||
|
|
||
|
void checkProperty()
|
||
|
{
|
||
|
bool flag = mpWidget->isPropertyTouched( maPropName, maPropKind );
|
||
|
|
||
|
if ( mpFlag && mpFlag->IsChecked() != flag )
|
||
|
{
|
||
|
CheckFlag( flag, true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CheckFlag( bool bValue, bool bBlockCallback )
|
||
|
{
|
||
|
if ( bBlockCallback )
|
||
|
mbBlockFlagCallback = true;
|
||
|
mpFlag->Check( bValue );
|
||
|
mbBlockFlagCallback = false;
|
||
|
}
|
||
|
|
||
|
bool bFirstGet; // HACK
|
||
|
rtl::OUString getValue()
|
||
|
{
|
||
|
// return mpWidget->getOriProperty( maPropName );
|
||
|
rtl::OUString value;
|
||
|
if ( bFirstGet ) // king of ugliness
|
||
|
value = mpWidget->getProperty( maPropName, maPropKind );
|
||
|
else
|
||
|
value = mpWidget->getOriginalProperty( maPropName, maPropKind );
|
||
|
bFirstGet = false;
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
// FIXME: wrapper should have a base class for this...
|
||
|
virtual layout::Window *getWindow() = 0;
|
||
|
virtual layout::Container *getContainer() { return NULL; }
|
||
|
|
||
|
virtual void load() = 0;
|
||
|
virtual void store() = 0;
|
||
|
|
||
|
Widget *mpWidget;
|
||
|
rtl::OUString maPropName;
|
||
|
Widget::PropertyKind maPropKind;
|
||
|
layout::CheckBox *mpFlag;
|
||
|
bool mbBlockFlagCallback;
|
||
|
};
|
||
|
|
||
|
struct AnyEdit : public AnyWidget, layout::HBox
|
||
|
{
|
||
|
layout::Edit *mpEdit;
|
||
|
bool mbMultiLine;
|
||
|
layout::PushButton *mpExpand;
|
||
|
DECL_LINK( ExpandEditHdl, layout::PushButton* );
|
||
|
|
||
|
// so we can create widgets (like transforming the Edit into a
|
||
|
// MultiLineEdit)
|
||
|
layout::Window *mpWinParent;
|
||
|
|
||
|
AnyEdit( Widget *pWidget, rtl::OUString aPropName,
|
||
|
Widget::PropertyKind aPropKind, layout::Window *pWinParent )
|
||
|
: AnyWidget( pWidget, aPropName, aPropKind ), layout::HBox( 0, false ), mpWinParent( pWinParent )
|
||
|
{
|
||
|
mpEdit = NULL;
|
||
|
mpExpand = new layout::PushButton( pWinParent, WB_TOGGLE );
|
||
|
mpExpand->SetToggleHdl( LINK( this, AnyEdit, ExpandEditHdl ) );
|
||
|
setAsMultiLine( false );
|
||
|
|
||
|
load();
|
||
|
}
|
||
|
|
||
|
virtual ~AnyEdit()
|
||
|
{
|
||
|
delete mpEdit;
|
||
|
delete mpExpand;
|
||
|
}
|
||
|
|
||
|
virtual layout::Window *getWindow()
|
||
|
{ return NULL; }
|
||
|
virtual layout::Container *getContainer()
|
||
|
{ return this; }
|
||
|
|
||
|
void setAsMultiLine( bool bMultiLine )
|
||
|
{
|
||
|
Clear();
|
||
|
XubString text;
|
||
|
if ( mpEdit )
|
||
|
{
|
||
|
text = mpEdit->GetText();
|
||
|
printf("Remove mpEdit and expand\n");
|
||
|
Remove( mpEdit );
|
||
|
Remove( mpExpand );
|
||
|
delete mpEdit;
|
||
|
}
|
||
|
|
||
|
if ( bMultiLine )
|
||
|
{
|
||
|
mpEdit = new layout::Edit( mpWinParent, WB_BORDER );
|
||
|
mpExpand->SetText( String::CreateFromAscii( "-" ) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mpEdit = new layout::Edit( mpWinParent, WB_BORDER );
|
||
|
mpExpand->SetText( String::CreateFromAscii( "+" ) );
|
||
|
}
|
||
|
|
||
|
mpEdit->SetText( text );
|
||
|
mpEdit->SetModifyHdl( LINK( this, AnyEdit, ApplyPropertyHdl ) );
|
||
|
|
||
|
Add( mpEdit, true, true, 0 );
|
||
|
Add( mpExpand, false, true, 0 );
|
||
|
|
||
|
mbMultiLine = bMultiLine;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
// TODO: make this global... We'll likely need it for export...
|
||
|
struct Translate {
|
||
|
const char *ori, *dest;
|
||
|
};
|
||
|
static rtl::OUString stringReplace( rtl::OUString _str,
|
||
|
Translate *trans )
|
||
|
{
|
||
|
const sal_Unicode *str = _str.getStr();
|
||
|
rtl::OUStringBuffer buf;
|
||
|
int i, j, k;
|
||
|
for ( i = 0; i < _str.getLength(); i++ )
|
||
|
{
|
||
|
for ( j = 0; trans[ j ].ori; j++ )
|
||
|
{
|
||
|
const char *ori = trans[ j ].ori;
|
||
|
for ( k = 0; ori[ k ] && i+k < _str.getLength(); k++ )
|
||
|
if ( ori[ k ] != str[ i+k ] )
|
||
|
break;
|
||
|
if ( !ori[ k ] )
|
||
|
{
|
||
|
// found substring
|
||
|
buf.appendAscii( trans[ j ].dest );
|
||
|
i += k;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
buf.append( str[ i ] );
|
||
|
}
|
||
|
return buf.makeStringAndClear();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
virtual void load()
|
||
|
{
|
||
|
#if 0
|
||
|
// replace end of lines by "\\n" strings
|
||
|
Translate trans[] = {
|
||
|
{ "\\", "\\\\" }, { "\n", "\\n" }, { 0, 0 }
|
||
|
};
|
||
|
rtl::OUString str = anyToString( getValue() );
|
||
|
str = stringReplace( str, trans );
|
||
|
SetText( str );
|
||
|
#endif
|
||
|
mpEdit->SetText( getValue() );
|
||
|
checkProperty();
|
||
|
}
|
||
|
|
||
|
virtual void store()
|
||
|
{
|
||
|
#if 0
|
||
|
// replace "\\n" strings by actual end of lines
|
||
|
Translate trans[] = {
|
||
|
{ "\\\\", "\\" }, { "\\n", "\n" },
|
||
|
{ "\\", "" }, { 0, 0 }
|
||
|
};
|
||
|
rtl::OUString str = GetText();
|
||
|
str = stringReplace( str, trans );
|
||
|
save( uno::makeAny( str ) );
|
||
|
#endif
|
||
|
save( uno::makeAny( (rtl::OUString) mpEdit->GetText() ) );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct AnyInteger : public AnyWidget, NumericField
|
||
|
{
|
||
|
AnyInteger( Widget *pWidget, rtl::OUString aPropName,
|
||
|
Widget::PropertyKind aPropKind, Window *pWinParent )
|
||
|
: AnyWidget( pWidget, aPropName, aPropKind ), NumericField( pWinParent, WB_SPIN|WB_BORDER )
|
||
|
{
|
||
|
load();
|
||
|
SetModifyHdl( LINK( this, AnyInteger, ApplyPropertyHdl ) );
|
||
|
}
|
||
|
|
||
|
virtual Window *getWindow()
|
||
|
{ return this; }
|
||
|
|
||
|
virtual void load()
|
||
|
{
|
||
|
OUString text = getValue();
|
||
|
SetText( text.getStr() );
|
||
|
checkProperty();
|
||
|
}
|
||
|
|
||
|
virtual void store()
|
||
|
{
|
||
|
fprintf(stderr, "store number: %ld\n", rtl::OUString( GetText() ).toInt64());
|
||
|
save( uno::makeAny( rtl::OUString( GetText() ).toInt64() ) );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct AnyFloat : public AnyInteger
|
||
|
{
|
||
|
AnyFloat( Widget *pWidget, rtl::OUString aPropName,
|
||
|
Widget::PropertyKind aPropKind, Window *pWinParent )
|
||
|
: AnyInteger( pWidget, aPropName, aPropKind, pWinParent )
|
||
|
{}
|
||
|
|
||
|
virtual void store()
|
||
|
{
|
||
|
save( uno::makeAny( rtl::OUString( GetText() ).toDouble() ) );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct AnyCheckBox : public AnyWidget, layout::CheckBox
|
||
|
{
|
||
|
AnyCheckBox( Widget *pWidget, rtl::OUString aPropName,
|
||
|
Widget::PropertyKind aPropKind, layout::Window *pWinParent )
|
||
|
: AnyWidget( pWidget, aPropName, aPropKind ), layout::CheckBox( pWinParent )
|
||
|
{
|
||
|
// adding some whitespaces to make the hit area larger
|
||
|
// SetText( String::CreateFromAscii( "" ) );
|
||
|
load();
|
||
|
SetToggleHdl( LINK( this, AnyWidget, ApplyPropertyHdl ) );
|
||
|
}
|
||
|
|
||
|
virtual ~AnyCheckBox()
|
||
|
{
|
||
|
fprintf(stderr, "~AnyCheckBox\n");
|
||
|
}
|
||
|
|
||
|
virtual layout::Window *getWindow()
|
||
|
{ return this; }
|
||
|
|
||
|
virtual void load()
|
||
|
{
|
||
|
fprintf(stderr, "loading boolean value\n");
|
||
|
Check( getValue().toInt64() );
|
||
|
setLabel();
|
||
|
checkProperty();
|
||
|
}
|
||
|
|
||
|
virtual void store()
|
||
|
{
|
||
|
save( uno::makeAny( IsChecked() ) );
|
||
|
setLabel();
|
||
|
}
|
||
|
|
||
|
void setLabel()
|
||
|
{
|
||
|
SetText( String::CreateFromAscii( IsChecked() ? "true" : "false" ) );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct AnyListBox : public AnyWidget, layout::ListBox
|
||
|
{
|
||
|
AnyListBox( Widget *pWidget, rtl::OUString aPropName,
|
||
|
Widget::PropertyKind aPropKind, Window *pWinParent )
|
||
|
: AnyWidget( pWidget, aPropName, aPropKind ), layout::ListBox( pWinParent, WB_DROPDOWN )
|
||
|
{
|
||
|
SetSelectHdl( LINK( this, AnyWidget, ApplyPropertyHdl ) );
|
||
|
}
|
||
|
|
||
|
virtual layout::Window *getWindow()
|
||
|
{ return this; }
|
||
|
|
||
|
virtual void load()
|
||
|
{
|
||
|
SelectEntryPos( getValue().toInt32() );
|
||
|
checkProperty();
|
||
|
}
|
||
|
|
||
|
virtual void store()
|
||
|
{
|
||
|
save( uno::makeAny( (short) GetSelectEntryPos() ) );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct AnyAlign : public AnyListBox
|
||
|
{
|
||
|
AnyAlign( Widget *pWidget, rtl::OUString aPropName,
|
||
|
Widget::PropertyKind aPropKind, Window *pWinParent )
|
||
|
: AnyListBox( pWidget, aPropName, aPropKind, pWinParent )
|
||
|
{
|
||
|
InsertEntry( XubString::CreateFromAscii( "Left" ) );
|
||
|
InsertEntry( XubString::CreateFromAscii( "Center" ) );
|
||
|
InsertEntry( XubString::CreateFromAscii( "Right" ) );
|
||
|
load();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/* AnyListBox and AnyComboBox different in that a ComboBox allows the user
|
||
|
to add other options, operating in strings, instead of constants.
|
||
|
(its more like a suggestive AnyEdit) */
|
||
|
struct AnyComboBox : public AnyWidget, layout::ComboBox
|
||
|
{
|
||
|
AnyComboBox( Widget *pWidget, rtl::OUString aPropName,
|
||
|
Widget::PropertyKind aPropKind, Window *pWinParent )
|
||
|
: AnyWidget( pWidget, aPropName, aPropKind ), layout::ComboBox( pWinParent, WB_DROPDOWN )
|
||
|
{
|
||
|
SetModifyHdl( LINK( this, AnyComboBox, ApplyPropertyHdl ) );
|
||
|
}
|
||
|
|
||
|
virtual layout::Window *getWindow()
|
||
|
{ return this; }
|
||
|
|
||
|
virtual void load()
|
||
|
{
|
||
|
SetText( getValue() );
|
||
|
checkProperty();
|
||
|
}
|
||
|
|
||
|
virtual void store()
|
||
|
{
|
||
|
save( uno::makeAny( (rtl::OUString) GetText() ) );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct AnyFontStyle : public AnyComboBox
|
||
|
{
|
||
|
AnyFontStyle( Widget *pWidget, rtl::OUString aPropName,
|
||
|
Widget::PropertyKind aPropKind, Window *pWinParent )
|
||
|
: AnyComboBox( pWidget, aPropName, aPropKind, pWinParent )
|
||
|
{
|
||
|
InsertEntry( XubString::CreateFromAscii( "Bold" ) );
|
||
|
InsertEntry( XubString::CreateFromAscii( "Italic" ) );
|
||
|
InsertEntry( XubString::CreateFromAscii( "Bold Italic" ) );
|
||
|
InsertEntry( XubString::CreateFromAscii( "Fett" ) );
|
||
|
load();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
layout::FixedText *mpLabel;
|
||
|
layout::CheckBox *mpFlag;
|
||
|
AnyWidget *mpValue;
|
||
|
|
||
|
public:
|
||
|
PropertyEntry( layout::Window *pWinParent, AnyWidget *pAnyWidget )
|
||
|
{
|
||
|
mpLabel = new layout::FixedText( pWinParent );
|
||
|
{
|
||
|
// append ':' to aPropName
|
||
|
rtl::OUStringBuffer buf( pAnyWidget->maPropName );
|
||
|
buf.append( sal_Unicode (':') );
|
||
|
mpLabel->SetText( buf.makeStringAndClear() );
|
||
|
}
|
||
|
mpValue = pAnyWidget;
|
||
|
mpFlag = new layout::CheckBox( pWinParent );
|
||
|
mpFlag->SetToggleHdl( LINK( mpValue, AnyWidget, FlagToggledHdl ) );
|
||
|
mpValue->mpFlag = mpFlag;
|
||
|
}
|
||
|
|
||
|
~PropertyEntry()
|
||
|
{
|
||
|
fprintf(stderr, "REMOVING label, flag and value\n");
|
||
|
delete mpLabel;
|
||
|
delete mpFlag;
|
||
|
delete mpValue;
|
||
|
}
|
||
|
|
||
|
// Use this factory rather than the constructor -- check for NULL
|
||
|
static PropertyEntry *construct( Widget *pWidget, rtl::OUString aPropName,
|
||
|
Widget::PropertyKind aPropKind, sal_uInt16 nType,
|
||
|
layout::Window *pWinParent )
|
||
|
{
|
||
|
AnyWidget *pAnyWidget;
|
||
|
switch (nType) {
|
||
|
case uno::TypeClass_STRING:
|
||
|
if ( aPropName.compareToAscii( "FontStyleName" ) == 0 )
|
||
|
{
|
||
|
pAnyWidget = new AnyFontStyle( pWidget, aPropName, aPropKind, pWinParent );
|
||
|
break;
|
||
|
}
|
||
|
pAnyWidget = new AnyEdit( pWidget, aPropName, aPropKind, pWinParent );
|
||
|
break;
|
||
|
case uno::TypeClass_SHORT:
|
||
|
if ( aPropName.compareToAscii( "Align" ) == 0 )
|
||
|
{
|
||
|
pAnyWidget = new AnyAlign( pWidget, aPropName, aPropKind, pWinParent );
|
||
|
break;
|
||
|
}
|
||
|
// otherwise, treat as any other number...
|
||
|
case uno::TypeClass_LONG:
|
||
|
case uno::TypeClass_UNSIGNED_LONG:
|
||
|
pAnyWidget = new AnyInteger( pWidget, aPropName, aPropKind, pWinParent );
|
||
|
break;
|
||
|
case uno::TypeClass_FLOAT:
|
||
|
case uno::TypeClass_DOUBLE:
|
||
|
pAnyWidget = new AnyFloat( pWidget, aPropName, aPropKind, pWinParent );
|
||
|
break;
|
||
|
case uno::TypeClass_BOOLEAN:
|
||
|
pAnyWidget = new AnyCheckBox( pWidget, aPropName, aPropKind, pWinParent );
|
||
|
break;
|
||
|
default:
|
||
|
return NULL;
|
||
|
}
|
||
|
return new PropertyEntry( pWinParent, pAnyWidget );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
layout::Window *mpParentWindow;
|
||
|
|
||
|
std::list< PropertyEntry* > maPropertiesList;
|
||
|
layout::FixedLine *mpSeparator;
|
||
|
|
||
|
// some properties are obscure, or simply don't make sense in this
|
||
|
// context. Let's just ignore them.
|
||
|
// Maybe we could offer them in an expander or something...
|
||
|
static bool toIgnore( rtl::OUString prop )
|
||
|
{
|
||
|
// binary search -- keep the list sorted alphabetically
|
||
|
static char const *toIgnoreList[] = {
|
||
|
"DefaultControl", "FocusOnClick", "FontCharWidth", "FontCharset",
|
||
|
"FontEmphasisMark", "FontFamily", "FontHeight", "FontKerning", "FontName",
|
||
|
"FontOrientation", "FontPitch", "FontRelief", "FontSlant", "FontStrikeout",
|
||
|
"FontType", "FontWordLineMode", "HelpText", "HelpURL", "MultiLine",
|
||
|
"Printable", "Repeat", "RepeatDelay", "Tabstop"
|
||
|
};
|
||
|
|
||
|
#if 0
|
||
|
// checks list sanity -- enable this when you add some entries...
|
||
|
for ( unsigned int i = 1; i < sizeof( toIgnoreList )/sizeof( char * ); i++ )
|
||
|
{
|
||
|
if ( strcmp(toIgnoreList[i-1], toIgnoreList[i]) >= 0 )
|
||
|
{
|
||
|
printf("ignore list not ordered properly: "
|
||
|
"'%s' should come before '%s'\n",
|
||
|
toIgnoreList[i], toIgnoreList[i-1]);
|
||
|
exit(-1);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
int min = 0, max = sizeof( toIgnoreList )/sizeof( char * ) - 1, mid, cmp;
|
||
|
do {
|
||
|
mid = min + (max - min)/2;
|
||
|
cmp = prop.compareToAscii( toIgnoreList[ mid ] );
|
||
|
if ( cmp > 0 )
|
||
|
min = mid+1;
|
||
|
else if ( cmp < 0 )
|
||
|
max = mid-1;
|
||
|
else
|
||
|
return true;
|
||
|
} while ( min <= max );
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
PropertiesList( layout::Dialog *dialog )
|
||
|
: layout::Table( dialog, "properties-box" )
|
||
|
, mpParentWindow( dialog ), mpSeparator( 0 )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
~PropertiesList()
|
||
|
{
|
||
|
clear();
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// auxiliary, add properties from the peer to the list
|
||
|
void addProperties( Widget *pWidget, Widget::PropertyKind rKind )
|
||
|
{
|
||
|
Widget::PropertyIterator it( pWidget, rKind );
|
||
|
while ( it.hasNext() )
|
||
|
{
|
||
|
beans::Property prop = it.next();
|
||
|
rtl::OUString name( prop.Name );
|
||
|
if ( toIgnore( name ) )
|
||
|
continue;
|
||
|
sal_uInt16 type = prop.Type.getTypeClass();
|
||
|
|
||
|
PropertyEntry *propEntry = PropertyEntry::construct(
|
||
|
pWidget, name, rKind, type, mpParentWindow );
|
||
|
|
||
|
if ( propEntry )
|
||
|
{
|
||
|
Add( propEntry->mpLabel, false, false );
|
||
|
// HACK: one of these will return Null...
|
||
|
Add( propEntry->mpValue->getWindow(), true, false );
|
||
|
Add( propEntry->mpValue->getContainer(), true, false );
|
||
|
|
||
|
Add( propEntry->mpFlag, false, false );
|
||
|
maPropertiesList.push_back( propEntry );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
void selectedWidget( Widget *pWidget )
|
||
|
{
|
||
|
clear();
|
||
|
if ( !pWidget )
|
||
|
return;
|
||
|
|
||
|
addProperties( pWidget, Widget::CONTAINER_PROPERTY );
|
||
|
|
||
|
mpSeparator = new layout::FixedLine( mpParentWindow );
|
||
|
// TODO: we may want to have to separate list widgets here...
|
||
|
Add( mpSeparator, false, false, 3, 1 );
|
||
|
|
||
|
addProperties( pWidget, Widget::WINDOW_PROPERTY );
|
||
|
|
||
|
ShowAll( true );
|
||
|
}
|
||
|
|
||
|
void clear()
|
||
|
{
|
||
|
Container::Clear();
|
||
|
|
||
|
for ( std::list< PropertyEntry* >::iterator it = maPropertiesList.begin();
|
||
|
it != maPropertiesList.end(); it++)
|
||
|
delete *it;
|
||
|
maPropertiesList.clear();
|
||
|
|
||
|
delete mpSeparator;
|
||
|
mpSeparator = NULL;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
IMPL_LINK( PropertiesList::PropertyEntry::AnyWidget, ApplyPropertyHdl, layout::Window *, pWin )
|
||
|
{
|
||
|
(void) pWin;
|
||
|
store();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
IMPL_LINK( PropertiesList::PropertyEntry::AnyWidget, FlagToggledHdl, layout::CheckBox *, pCheck )
|
||
|
{
|
||
|
fprintf(stderr, "Property flag pressed -- is: %d\n", pCheck->IsChecked());
|
||
|
if ( !mbBlockFlagCallback )
|
||
|
{
|
||
|
bool checked = pCheck->IsChecked();
|
||
|
if ( !checked ) // revert
|
||
|
{
|
||
|
fprintf(stderr, "revert\n");
|
||
|
load();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fprintf(stderr, "user can't dirty the flag!\n");
|
||
|
// User can't flag the property as dirty
|
||
|
// Actually, we may want to allow the designer to force a property to be stored.
|
||
|
// Could be useful when the default value of some new property wasn't yet decided...
|
||
|
CheckFlag( false, true );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
fprintf(stderr, "Property flag pressed -- BLOCKED\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
IMPL_LINK( PropertiesList::PropertyEntry::AnyEdit, ExpandEditHdl, layout::PushButton *, pBtn )
|
||
|
{
|
||
|
setAsMultiLine( pBtn->IsChecked() );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//** SortListBox auxiliary widget
|
||
|
|
||
|
class SortListBox
|
||
|
{ // For a manual sort ListBox; asks for a ListBox and Up/Down/Remove
|
||
|
// buttons to wrap
|
||
|
DECL_LINK( ItemSelectedHdl, layout::ListBox* );
|
||
|
DECL_LINK( UpPressedHdl, layout::Button* );
|
||
|
DECL_LINK( DownPressedHdl, layout::Button* );
|
||
|
DECL_LINK( RemovePressedHdl, layout::Button* );
|
||
|
layout::PushButton *mpUpButton, *mpDownButton, *mpRemoveButton;
|
||
|
|
||
|
protected:
|
||
|
layout::ListBox *mpListBox;
|
||
|
|
||
|
virtual void upPressed( USHORT nPos )
|
||
|
{
|
||
|
XubString str = mpListBox->GetSelectEntry();
|
||
|
mpListBox->RemoveEntry( nPos );
|
||
|
nPos = mpListBox->InsertEntry( str, nPos-1 );
|
||
|
mpListBox->SelectEntryPos( nPos );
|
||
|
}
|
||
|
|
||
|
virtual void downPressed( USHORT nPos )
|
||
|
{
|
||
|
XubString str = mpListBox->GetSelectEntry();
|
||
|
mpListBox->RemoveEntry( nPos );
|
||
|
nPos = mpListBox->InsertEntry( str, nPos+1 );
|
||
|
mpListBox->SelectEntryPos( nPos );
|
||
|
}
|
||
|
|
||
|
virtual void removePressed( USHORT nPos )
|
||
|
{
|
||
|
mpListBox->RemoveEntry( nPos );
|
||
|
}
|
||
|
|
||
|
virtual void itemSelected( USHORT nPos )
|
||
|
{
|
||
|
// if we had some XLayoutContainer::canAdd() or maxChildren() function
|
||
|
// we could make a function to check if we can move selected and enable/
|
||
|
// /disable the move buttons as appropriate
|
||
|
|
||
|
if ( nPos == LISTBOX_ENTRY_NOTFOUND )
|
||
|
{
|
||
|
mpUpButton->Disable();
|
||
|
mpDownButton->Disable();
|
||
|
mpRemoveButton->Disable();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mpUpButton->Enable();
|
||
|
mpDownButton->Enable();
|
||
|
mpRemoveButton->Enable();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
SortListBox( layout::ListBox *pListBox, layout::PushButton *pUpButton, layout::PushButton *pDownButton,
|
||
|
layout::PushButton *pRemoveButton )
|
||
|
: mpUpButton( pUpButton), mpDownButton( pDownButton), mpRemoveButton( pRemoveButton ),
|
||
|
mpListBox( pListBox )
|
||
|
{
|
||
|
mpListBox->SetSelectHdl( LINK( this, SortListBox, ItemSelectedHdl ) );
|
||
|
|
||
|
mpUpButton->SetModeImage( layout::Image ( "res/commandimagelist/lc_moveup.png" ) );
|
||
|
mpUpButton->SetImageAlign( IMAGEALIGN_LEFT );
|
||
|
mpUpButton->SetClickHdl( LINK( this, SortListBox, UpPressedHdl ) );
|
||
|
|
||
|
mpDownButton->SetModeImage( layout::Image ( "res/commandimagelist/lc_movedown.png" ) );
|
||
|
mpDownButton->SetImageAlign( IMAGEALIGN_LEFT );
|
||
|
mpDownButton->SetClickHdl( LINK( this, SortListBox, DownPressedHdl ) );
|
||
|
|
||
|
// "res/commandimagelist/lch_delete.png", "res/commandimagelist/lc_delete.png"
|
||
|
mpRemoveButton->SetModeImage( layout::Image ( "res/commandimagelist/sc_closedoc.png" ) );
|
||
|
mpRemoveButton->SetImageAlign( IMAGEALIGN_LEFT );
|
||
|
mpRemoveButton->SetClickHdl( LINK( this, SortListBox, RemovePressedHdl ) );
|
||
|
|
||
|
// fire an un-select event
|
||
|
itemSelected( LISTBOX_ENTRY_NOTFOUND );
|
||
|
}
|
||
|
|
||
|
~SortListBox()
|
||
|
{
|
||
|
delete mpListBox;
|
||
|
delete mpUpButton;
|
||
|
delete mpDownButton;
|
||
|
delete mpRemoveButton;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
IMPL_LINK( SortListBox, UpPressedHdl, layout::Button *, pBtn )
|
||
|
{
|
||
|
(void) pBtn;
|
||
|
USHORT pos = mpListBox->GetSelectEntryPos();
|
||
|
if ( pos > 0 && pos != LISTBOX_ENTRY_NOTFOUND )
|
||
|
upPressed( pos );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
IMPL_LINK( SortListBox, DownPressedHdl, layout::Button *, pBtn )
|
||
|
{
|
||
|
(void) pBtn;
|
||
|
USHORT pos = mpListBox->GetSelectEntryPos();
|
||
|
if ( pos < mpListBox->GetEntryCount() && pos != LISTBOX_ENTRY_NOTFOUND )
|
||
|
downPressed( pos );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
IMPL_LINK( SortListBox, RemovePressedHdl, layout::Button *, pBtn )
|
||
|
{
|
||
|
(void) pBtn;
|
||
|
USHORT pos = mpListBox->GetSelectEntryPos();
|
||
|
if ( pos != LISTBOX_ENTRY_NOTFOUND )
|
||
|
removePressed( pos );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
IMPL_LINK( SortListBox, ItemSelectedHdl, layout::ListBox *, pList )
|
||
|
{
|
||
|
(void) pList;
|
||
|
USHORT pos = mpListBox->GetSelectEntryPos();
|
||
|
itemSelected( pos );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//** LayoutTree widget
|
||
|
|
||
|
class LayoutTree : public SortListBox
|
||
|
{
|
||
|
public:
|
||
|
struct Listener
|
||
|
{
|
||
|
virtual void widgetSelected( Widget *pWidget ) = 0;
|
||
|
};
|
||
|
|
||
|
private:
|
||
|
Listener *mpListener;
|
||
|
|
||
|
public:
|
||
|
Widget *mpRootWidget;
|
||
|
|
||
|
LayoutTree( layout::Dialog *dialog )
|
||
|
: SortListBox( new layout::ListBox( dialog, "layout-tree" ),
|
||
|
new layout::PushButton( dialog, "layout-up-button" ),
|
||
|
new layout::PushButton( dialog, "layout-down-button" ),
|
||
|
new layout::PushButton( dialog, "layout-remove-button" ) )
|
||
|
{
|
||
|
layout::PeerHandle handle = dialog->GetPeerHandle( "preview-box" );
|
||
|
uno::Reference< awt::XLayoutConstrains > xWidget( handle, uno::UNO_QUERY );
|
||
|
mpRootWidget = new Widget( xWidget, "root" );
|
||
|
}
|
||
|
|
||
|
~LayoutTree()
|
||
|
{
|
||
|
delete mpRootWidget;
|
||
|
}
|
||
|
|
||
|
Widget *getWidget( int nPos )
|
||
|
{
|
||
|
if ( nPos != LISTBOX_ENTRY_NOTFOUND )
|
||
|
return FlatLayout::get( mpRootWidget, nPos );
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
Widget *getSelectedWidget()
|
||
|
{
|
||
|
Widget *pWidget = getWidget( mpListBox->GetSelectEntryPos() );
|
||
|
if ( !pWidget ) // return root, if none selected
|
||
|
pWidget = mpRootWidget;
|
||
|
return pWidget;
|
||
|
}
|
||
|
|
||
|
void selectWidget( Widget *pWidget )
|
||
|
{
|
||
|
int pos = FlatLayout::get( mpRootWidget, pWidget );
|
||
|
if ( pos == -1 )
|
||
|
// if asked to select hidden root, select visible root
|
||
|
pos = 0;
|
||
|
mpListBox->SelectEntryPos( pos );
|
||
|
}
|
||
|
|
||
|
void rebuild()
|
||
|
{
|
||
|
struct inner
|
||
|
{
|
||
|
// pads a string with whitespaces
|
||
|
static rtl::OUString padString( rtl::OUString name, int depth )
|
||
|
{
|
||
|
rtl::OStringBuffer aBuf( depth * 4 + name.getLength() + 2 );
|
||
|
for (int i = 0; i < depth; i++)
|
||
|
aBuf.append( " " );
|
||
|
aBuf.append( rtl::OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ) );
|
||
|
return rtl::OUString( aBuf.getStr(), aBuf.getLength(),
|
||
|
RTL_TEXTENCODING_UTF8 );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
mpListBox->Clear();
|
||
|
for ( Widget *i = FlatLayout::next( mpRootWidget ); i; i = FlatLayout::next( i ) )
|
||
|
mpListBox->InsertEntry( inner::padString( i->getLabel(), i->getDepth()-1 ) );
|
||
|
|
||
|
// any selection, no longer is. ListBox doesn't fire the event on this case;
|
||
|
// force it.
|
||
|
itemSelected( LISTBOX_ENTRY_NOTFOUND );
|
||
|
}
|
||
|
|
||
|
void setListener( Listener *pListener )
|
||
|
{ mpListener = pListener; }
|
||
|
|
||
|
// print in XML format...
|
||
|
|
||
|
static rtl::OUString toXMLNaming (const rtl::OUString &string)
|
||
|
{
|
||
|
rtl::OUStringBuffer buffer (string.getLength());
|
||
|
sal_Unicode *str = string.pData->buffer;
|
||
|
for (int i = 0; i < string.getLength(); i++) {
|
||
|
if ( str[i] >= 'A' && str[i] <= 'Z' )
|
||
|
{
|
||
|
if ( i > 0 )
|
||
|
buffer.append ((sal_Unicode) '-');
|
||
|
buffer.append ((sal_Unicode) (str[i] - 'A' + 'a'));
|
||
|
}
|
||
|
else
|
||
|
buffer.append ((sal_Unicode) str[i]);
|
||
|
}
|
||
|
|
||
|
return buffer.makeStringAndClear();
|
||
|
}
|
||
|
|
||
|
void print()
|
||
|
{
|
||
|
printf("\t\tExport:\n");
|
||
|
printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||
|
"<dialog xmlns=\"http://openoffice.org/2007/layout\"\n"
|
||
|
" xmlns:cnt=\"http://openoffice.org/2007/layout/container\"\n"
|
||
|
" id=\"dialog\" title=\"Unnamed\" sizeable=\"true\" >\n");
|
||
|
|
||
|
for ( Widget *i = FlatLayout::next( mpRootWidget ); i; i = FlatLayout::next( i ) )
|
||
|
{
|
||
|
for ( int d = i->getDepth(); d > 0; d-- )
|
||
|
printf(" ");
|
||
|
printf("<%s ", OUSTRING_CSTR( i->getUnoName() ) );
|
||
|
|
||
|
for ( int kind = 0; kind < 2; kind++ )
|
||
|
{
|
||
|
Widget::PropertyKind wKind = kind == 0 ? Widget::WINDOW_PROPERTY
|
||
|
: Widget::CONTAINER_PROPERTY;
|
||
|
Widget::PropertyIterator it( i, wKind );
|
||
|
while ( it.hasNext() )
|
||
|
{
|
||
|
beans::Property prop = it.next();
|
||
|
if ( !i->isPropertyTouched( prop.Name, wKind ) )
|
||
|
continue;
|
||
|
|
||
|
rtl::OUString value = i->getProperty( prop.Name, wKind );
|
||
|
if ( prop.Type.getTypeClass() == uno::TypeClass_BOOLEAN )
|
||
|
{
|
||
|
if ( value.compareToAscii( "0" ) )
|
||
|
value = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("false") );
|
||
|
else
|
||
|
value = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("true") );
|
||
|
}
|
||
|
|
||
|
if ( value.getLength() > 0 )
|
||
|
printf("%s%s=\"%s\" ",
|
||
|
kind == 0 ? "" : "cnt:",
|
||
|
OUSTRING_CSTR( toXMLNaming( prop.Name ) ), OUSTRING_CSTR( value )
|
||
|
);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
printf("/>\n");
|
||
|
}
|
||
|
printf("</dialog>\n");
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
virtual void upPressed( USHORT nPos )
|
||
|
{
|
||
|
Widget *pWidget = getWidget( nPos );
|
||
|
if ( FlatLayout::moveWidget( pWidget, true ) )
|
||
|
rebuild();
|
||
|
selectWidget( pWidget );
|
||
|
}
|
||
|
|
||
|
virtual void downPressed( USHORT nPos )
|
||
|
{
|
||
|
Widget *pWidget = getWidget( nPos );
|
||
|
if ( FlatLayout::moveWidget( pWidget, false ) )
|
||
|
rebuild();
|
||
|
selectWidget( pWidget );
|
||
|
}
|
||
|
|
||
|
virtual void removePressed( USHORT nPos )
|
||
|
{
|
||
|
Widget *pWidget = getWidget( nPos );
|
||
|
if ( pWidget )
|
||
|
{
|
||
|
pWidget->up()->removeChild( pWidget );
|
||
|
delete pWidget;
|
||
|
rebuild();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
virtual void itemSelected( USHORT nPos )
|
||
|
{
|
||
|
mpListener->widgetSelected( getWidget( nPos ) );
|
||
|
SortListBox::itemSelected( nPos );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//** EditorImpl
|
||
|
|
||
|
class EditorImpl : public LayoutTree::Listener
|
||
|
{
|
||
|
void createWidget( const char *unoName );
|
||
|
|
||
|
PropertiesList *mpPropertiesList;
|
||
|
LayoutTree *mpLayoutTree;
|
||
|
|
||
|
layout::PushButton *pImportButton, *pExportButton;
|
||
|
#ifdef FILEDLG
|
||
|
FileDialog *pImportDialog;
|
||
|
#endif
|
||
|
DECL_LINK( ImportButtonHdl, layout::PushButton* );
|
||
|
DECL_LINK( ExportButtonHdl, layout::PushButton* );
|
||
|
#ifdef FILEDLG
|
||
|
DECL_LINK( ImportDialogHdl, FileDialog* );
|
||
|
#endif
|
||
|
|
||
|
// framework stuff
|
||
|
uno::Reference< lang::XMultiServiceFactory > mxFactory;
|
||
|
uno::Reference< awt::XToolkit > mxToolkit;
|
||
|
uno::Reference< awt::XWindow > mxToplevel;
|
||
|
|
||
|
virtual void widgetSelected( Widget *pWidget );
|
||
|
DECL_LINK( CreateWidgetHdl, layout::Button* );
|
||
|
|
||
|
std::list< layout::PushButton *> maCreateButtons;
|
||
|
|
||
|
public:
|
||
|
|
||
|
EditorImpl( layout::Dialog *dialog,
|
||
|
// we should probable open this channel (or whatever its called) ourselves
|
||
|
uno::Reference< lang::XMultiServiceFactory > xMSF );
|
||
|
~EditorImpl();
|
||
|
|
||
|
void loadFile( const rtl::OUString &aTestFile );
|
||
|
};
|
||
|
|
||
|
EditorImpl::EditorImpl( layout::Dialog *dialog,
|
||
|
uno::Reference< lang::XMultiServiceFactory > xFactory )
|
||
|
: mxFactory( xFactory )
|
||
|
, mxToplevel( dialog->GetPeerHandle( "dialog" ), uno::UNO_QUERY )
|
||
|
// FIXME: any of these should work
|
||
|
//dialog->getContext()->getRoot(), uno::UNO_QUERY )
|
||
|
// dialog->GetPeer(), uno::UNO_QUERY )
|
||
|
{
|
||
|
fprintf (stderr, "EditorImpl()\n");
|
||
|
// framework
|
||
|
mxToolkit = uno::Reference< awt::XToolkit >(
|
||
|
mxFactory->createInstance(
|
||
|
rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.Toolkit" ) ) ),
|
||
|
uno::UNO_QUERY );
|
||
|
assert( mxToolkit.is() );
|
||
|
|
||
|
// custom widgets
|
||
|
fprintf (stderr, "custom widgets\n");
|
||
|
mpPropertiesList = new PropertiesList( dialog );
|
||
|
|
||
|
mpLayoutTree = new LayoutTree( dialog );
|
||
|
mpLayoutTree->setListener( this );
|
||
|
|
||
|
/* if ( xImport.is() )
|
||
|
mpLayoutTree->getWidget( -1 )->addChild( new Widget( xImport, "import" ) );*/
|
||
|
|
||
|
// create buttons
|
||
|
layout::Container aWidgets( dialog, "create-widget" );
|
||
|
layout::Container aContainers( dialog, "create-container" );
|
||
|
for ( int i = 0; i < WIDGETS_SPECS_LEN; i++ )
|
||
|
{
|
||
|
layout::PushButton *pBtn = new layout::PushButton( (layout::Window *) dialog );
|
||
|
pBtn->SetText( rtl::OUString::createFromAscii( WIDGETS_SPECS[ i ].pLabel ) );
|
||
|
pBtn->SetClickHdl( LINK( this, EditorImpl, CreateWidgetHdl ) );
|
||
|
if ( WIDGETS_SPECS[ i ].pIconName != NULL )
|
||
|
{
|
||
|
rtl::OString aPath ("res/commandimagelist/");
|
||
|
aPath += WIDGETS_SPECS[ i ].pIconName;
|
||
|
layout::Image aImg( aPath );
|
||
|
pBtn->SetModeImage( aImg );
|
||
|
pBtn->SetImageAlign( IMAGEALIGN_LEFT );
|
||
|
}
|
||
|
pBtn->Show();
|
||
|
maCreateButtons.push_back( pBtn );
|
||
|
layout::Container *pBox = WIDGETS_SPECS[ i ].bIsContainer ? &aContainers : &aWidgets;
|
||
|
pBox->Add( pBtn );
|
||
|
}
|
||
|
|
||
|
#ifdef FILEDLG
|
||
|
fprintf(stderr,"creating file dialog\n");
|
||
|
pImportDialog = new FileDialog( NULL/*(layout::Window *) dialog*/, 0 );
|
||
|
fprintf(stderr,"connecting it\n");
|
||
|
pImportDialog->SetFileSelectHdl( LINK( this, EditorImpl, ImportDialogHdl ) );
|
||
|
fprintf(stderr,"done file dialog\n");
|
||
|
#endif
|
||
|
|
||
|
/* pImportButton = new layout::PushButton( dialog, "import-button" );
|
||
|
pImportButton->SetClickHdl( LINK( this, EditorImpl, ImportButtonHdl ) );*/
|
||
|
pExportButton = new layout::PushButton( dialog, "export-button" );
|
||
|
pExportButton->SetClickHdl( LINK( this, EditorImpl, ExportButtonHdl ) );
|
||
|
}
|
||
|
|
||
|
EditorImpl::~EditorImpl()
|
||
|
{
|
||
|
delete mpPropertiesList;
|
||
|
delete mpLayoutTree;
|
||
|
for ( std::list< layout::PushButton * >::const_iterator i = maCreateButtons.begin();
|
||
|
i != maCreateButtons.end(); i++)
|
||
|
delete *i;
|
||
|
delete pImportButton;
|
||
|
delete pExportButton;
|
||
|
#ifdef FILEDLG
|
||
|
delete pImportDialog;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void EditorImpl::loadFile( const rtl::OUString &aTestFile )
|
||
|
{
|
||
|
fprintf( stderr, "TEST: layout instance\n" );
|
||
|
uno::Reference< awt::XLayoutRoot > xRoot
|
||
|
( new EditorRoot( mxFactory, mpLayoutTree->mpRootWidget ) );
|
||
|
|
||
|
/*
|
||
|
mxMSF->createInstance
|
||
|
( ::rtl::OUString::createFromAscii( "com.sun.star.awt.Layout" ) ),
|
||
|
uno::UNO_QUERY );
|
||
|
*/
|
||
|
if ( !xRoot.is() )
|
||
|
{
|
||
|
throw uno::RuntimeException(
|
||
|
OUString( RTL_CONSTASCII_USTRINGPARAM("could not create awt Layout component!") ),
|
||
|
uno::Reference< uno::XInterface >() );
|
||
|
}
|
||
|
|
||
|
fprintf( stderr, "TEST: initing root\n" );
|
||
|
uno::Reference< lang::XInitialization > xInit( xRoot, uno::UNO_QUERY );
|
||
|
if ( !xInit.is() )
|
||
|
{
|
||
|
throw uno::RuntimeException(
|
||
|
OUString( RTL_CONSTASCII_USTRINGPARAM("Layout has no XInitialization!") ),
|
||
|
uno::Reference< uno::XInterface >() );
|
||
|
}
|
||
|
|
||
|
fprintf( stderr, "TEST: running parser\n" );
|
||
|
uno::Sequence< uno::Any > aParams( 1 );
|
||
|
aParams[0] <<= aTestFile;
|
||
|
fprintf( stderr, "TEST: do it\n" );
|
||
|
xInit->initialize( aParams );
|
||
|
fprintf( stderr, "TEST: file loaded\n" );
|
||
|
|
||
|
mpLayoutTree->rebuild();
|
||
|
}
|
||
|
|
||
|
void EditorImpl::createWidget( const char *name )
|
||
|
{
|
||
|
Widget *pWidget = mpLayoutTree->getSelectedWidget();
|
||
|
|
||
|
Widget *pChild = new Widget( rtl::OUString(), mxToolkit, uno::Reference< awt::XLayoutContainer >( mxToplevel, uno::UNO_QUERY ), rtl::OUString::createFromAscii( name ), awt::WindowAttribute::SHOW );
|
||
|
if ( !pWidget->addChild( pChild ) )
|
||
|
{
|
||
|
delete pChild;
|
||
|
// we may want to popup an error message
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mpLayoutTree->rebuild();
|
||
|
mpLayoutTree->selectWidget( pWidget );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void EditorImpl::widgetSelected( Widget *pWidget )
|
||
|
{
|
||
|
// we know can't add widget to a non-container, so let's disable the create
|
||
|
// buttons then. Would be nice to have a method to check if a container is
|
||
|
// full as well...
|
||
|
if ( !pWidget || pWidget->isContainer() )
|
||
|
{
|
||
|
for ( std::list< layout::PushButton *>::const_iterator it = maCreateButtons.begin();
|
||
|
it != maCreateButtons.end(); it++)
|
||
|
(*it)->Enable();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for ( std::list< layout::PushButton *>::const_iterator it = maCreateButtons.begin();
|
||
|
it != maCreateButtons.end(); it++)
|
||
|
(*it)->Disable();
|
||
|
}
|
||
|
|
||
|
mpPropertiesList->selectedWidget( pWidget );
|
||
|
}
|
||
|
|
||
|
IMPL_LINK( EditorImpl, CreateWidgetHdl, layout::Button *, pBtn )
|
||
|
{
|
||
|
int i = 0;
|
||
|
for ( std::list< layout::PushButton *>::const_iterator it = maCreateButtons.begin();
|
||
|
it != maCreateButtons.end(); it++, i++ )
|
||
|
{
|
||
|
if ( pBtn == *it )
|
||
|
break;
|
||
|
}
|
||
|
assert( i < WIDGETS_SPECS_LEN );
|
||
|
createWidget( WIDGETS_SPECS[i].pName );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
IMPL_LINK( EditorImpl, ImportButtonHdl, layout::PushButton *, pBtn )
|
||
|
{
|
||
|
(void) pBtn;
|
||
|
fprintf(stderr, "IMPORT!\n");
|
||
|
#ifdef FILEDLG
|
||
|
pImportDialog->Execute();
|
||
|
#endif
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#ifdef FILEDLG
|
||
|
IMPL_LINK( EditorImpl, ImportDialogHdl, FileDialog *, pDialog )
|
||
|
{
|
||
|
//fprintf(stderr, "Executing import dialog!\n");
|
||
|
|
||
|
UniString path = pDialog->GetPath();
|
||
|
fprintf(stderr, "got import file: %s\n",rtl::OUStringToOString( path, RTL_TEXTENCODING_ASCII_US ).getStr() );
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
IMPL_LINK( EditorImpl, ExportButtonHdl, layout::PushButton *, pBtn )
|
||
|
{
|
||
|
(void) pBtn;
|
||
|
mpLayoutTree->print();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//** Editor, the Dialog
|
||
|
|
||
|
Editor::Editor( uno::Reference< lang::XMultiServiceFactory > xFactory,
|
||
|
rtl::OUString aFile )
|
||
|
: layout::Dialog( (Window*) (NULL), "editor.xml", "dialog" )
|
||
|
, mpImpl( new EditorImpl( this, xFactory ) )
|
||
|
{
|
||
|
if ( aFile.getLength() )
|
||
|
mpImpl->loadFile( aFile );
|
||
|
|
||
|
// parent:
|
||
|
FreeResource();
|
||
|
}
|
||
|
|
||
|
Editor::~Editor()
|
||
|
{
|
||
|
delete mpImpl;
|
||
|
}
|