diff options
Diffstat (limited to '')
35 files changed, 6147 insertions, 0 deletions
diff --git a/odk/examples/DevelopersGuide/Forms/BooleanValidator.java b/odk/examples/DevelopersGuide/Forms/BooleanValidator.java new file mode 100644 index 000000000..eb8851c2a --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/BooleanValidator.java @@ -0,0 +1,84 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +import com.sun.star.uno.AnyConverter; + +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +public class BooleanValidator extends ControlValidator +{ + private boolean m_preventChecked; + + /** Creates a new instance of BooleanValidator */ + public BooleanValidator( boolean preventChecked ) + { + m_preventChecked = preventChecked; + } + + public String explainInvalid( Object Value ) + { + try + { + if ( AnyConverter.isVoid( Value ) ) + return "'indetermined' is not an allowed state"; + boolean value = ((Boolean)Value).booleanValue(); + if ( m_preventChecked && ( value == true ) ) + return "no no no. Don't check it."; + } + catch( java.lang.Exception e ) + { + return "ooops. Unknown error"; + } + return ""; + } + + public boolean isValid( Object Value ) + { + try + { + if ( AnyConverter.isVoid( Value ) ) + return false; + + boolean value = ((Boolean)Value).booleanValue(); + if ( m_preventChecked && ( value == true ) ) + return false; + return true; + } + catch( java.lang.Exception e ) + { + } + return false; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/ButtonOperator.java b/odk/examples/DevelopersGuide/Forms/ButtonOperator.java new file mode 100644 index 000000000..890ea7251 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/ButtonOperator.java @@ -0,0 +1,219 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ +// java base stuff +import java.util.ArrayList; + +import com.sun.star.awt.ActionEvent; +import com.sun.star.awt.XActionListener; +import com.sun.star.awt.XButton; +import com.sun.star.beans.XPropertySet; +import com.sun.star.form.runtime.FormOperations; +import com.sun.star.form.runtime.XFeatureInvalidation; +import com.sun.star.form.runtime.XFormOperations; +import com.sun.star.lang.EventObject; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; + + +/**************************************************************************/ +/** a helper class for operating the buttons +*/ +public class ButtonOperator implements XActionListener, XFeatureInvalidation +{ + private XComponentContext m_componentContext; + private DocumentHelper m_aDocument; + private XPropertySet m_form; + private XFormOperations m_formOperations; + + private ArrayList<XPropertySet> m_aButtons; + + /* ------------------------------------------------------------------ */ + /** ctor + */ + public ButtonOperator( XComponentContext xCtx, DocumentHelper aDocument, XPropertySet _form ) + { + m_componentContext = xCtx; + m_aDocument = aDocument; + m_form = _form; + m_aButtons = new ArrayList<XPropertySet>(); + } + + /* ------------------------------------------------------------------ */ + private short getAssociatedFormFeature( XPropertySet _buttonModel ) + { + short formFeature = -1; + try + { + formFeature = Short.valueOf( (String)_buttonModel.getPropertyValue( "Tag" ) ); + } + catch( com.sun.star.uno.Exception e ) + { + } + return formFeature; + } + + /* ------------------------------------------------------------------ */ + /** gets the button which we operate and which is responsible for a given URL + */ + private XPropertySet getButton( short _formFeature ) + { + for ( int i=0; i < m_aButtons.size(); ++i ) + { + XPropertySet button = m_aButtons.get( i ); + if ( _formFeature == getAssociatedFormFeature( button ) ) + return button; + } + return null; + } + + /* ------------------------------------------------------------------ */ + /** announces a button which the operator should be responsible for + */ + private int getButtonIndex( XPropertySet xButton ) + { + int nPos = -1; + for ( int i=0; ( i < m_aButtons.size() ) && ( -1 == nPos ); ++i ) + { + if ( xButton.equals( m_aButtons.get( i ) ) ) + nPos = i; + } + return nPos; + } + + /* ------------------------------------------------------------------ */ + /** announces a button which the operator should be responsible for + */ + public void addButton( XPropertySet _buttonModel, short _formFeature ) throws java.lang.Exception + { + // the current view to the document + DocumentViewHelper aCurrentView = m_aDocument.getCurrentView(); + + // add a listener so we get noticed if the user presses the button + XButton xButtonControl = UnoRuntime.queryInterface( XButton.class, + aCurrentView.getFormControl( _buttonModel ) ); + xButtonControl.addActionListener( this ); + + _buttonModel.setPropertyValue( "Tag", String.valueOf( _formFeature ) ); + + // remember the button + m_aButtons.add( _buttonModel ); + } + + /* ------------------------------------------------------------------ */ + public void revokeButton( XPropertySet xButtonModel ) + { + int nPos = getButtonIndex( xButtonModel ); + if ( -1 < nPos ) + { + m_aButtons.remove( nPos ); + } + } + + /* ================================================================== + = XActionListener + ================================================================== */ + /* ------------------------------------------------------------------ */ + /* called when a button has been pressed + */ + public void actionPerformed( ActionEvent aEvent ) throws com.sun.star.uno.RuntimeException + { + // get the model's name + XPropertySet buttonModel = FLTools.getModel( aEvent.Source, XPropertySet.class ); + try + { + short formFeature = getAssociatedFormFeature( buttonModel ); + if ( formFeature != -1 ) + m_formOperations.execute( formFeature ); + } + catch( final com.sun.star.uno.Exception e ) + { + } + } + + /* ------------------------------------------------------------------ */ + /* (to be) called when the form layer has been switched to alive mode + * @todo + * register as listener somewhere ... + */ + public void onFormsAlive() + { + m_formOperations = FormOperations.createWithFormController( + m_componentContext, m_aDocument.getCurrentView().getFormController( m_form ) ); + m_formOperations.setFeatureInvalidation( this ); + invalidateAllFeatures(); + } + + /* ================================================================== + = XEventListener + ================================================================== */ + public void disposing( EventObject aEvent ) + { + // not interested in + } + + /* ================================================================== + = XFeatureInvalidation + ================================================================== */ + private void updateButtonState( XPropertySet _buttonModel, short _formFeature ) + { + try + { + _buttonModel.setPropertyValue( "Enabled", m_formOperations.isEnabled( _formFeature ) ); + } + catch( com.sun.star.uno.Exception e ) + { + } + } + + public void invalidateFeatures( short[] _features ) throws com.sun.star.uno.RuntimeException + { + for ( int i=0; i<_features.length; ++i ) + { + XPropertySet buttonModel = getButton( _features[i] ); + if ( buttonModel != null ) + updateButtonState( buttonModel, _features[i] ); + } + } + + public void invalidateAllFeatures() throws com.sun.star.uno.RuntimeException + { + for ( XPropertySet buttonModel : m_aButtons ) + { + updateButtonState( buttonModel, getAssociatedFormFeature( buttonModel ) ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/ComponentTreeTraversal.java b/odk/examples/DevelopersGuide/Forms/ComponentTreeTraversal.java new file mode 100644 index 000000000..be9bc22fb --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/ComponentTreeTraversal.java @@ -0,0 +1,92 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import com.sun.star.container.*; +import com.sun.star.lang.*; + +/**************************************************************************/ +/** an abstract interface for components doing an action on a form component +*/ +interface IFormComponentAction +{ + public abstract void handle( Object aFormComponent ) throws java.lang.Exception; +} + +/**************************************************************************/ +/** a helper class for travelling a form component tree +*/ +class ComponentTreeTraversal implements IFormComponentAction +{ + /* ------------------------------------------------------------------ */ + /** Indicator method to decide whether to step down the tree. + + <p>The default implementation checks if the container given is a grid + control model or a <service scope="com.sun.star.form">FormComponents</service> + instance.</p> + */ + protected boolean shouldStepInto( XIndexContainer xContainer ) + { + // step down the tree, if possible + XServiceInfo xSI = UNO.queryServiceInfo( xContainer ); + if ( null != xSI + && ( xSI.supportsService( "com.sun.star.form.FormComponents" ) + || xSI.supportsService( "com.sun.star.form.component.GridControl" ) + ) + ) + { + return true; + } + else + { + return false; + } + } + /* ------------------------------------------------------------------ */ + public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception + { + XIndexContainer xCont = UNO.queryIndexContainer( aFormComponent ); + if ( ( null != xCont ) + && shouldStepInto( xCont ) + ) + { + for ( int i=0; i<xCont.getCount(); ++i ) + { + handle( xCont.getByIndex( i ) ); + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/ControlLock.java b/odk/examples/DevelopersGuide/Forms/ControlLock.java new file mode 100644 index 000000000..6895f73f9 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/ControlLock.java @@ -0,0 +1,223 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import com.sun.star.uno.*; +import com.sun.star.lang.*; +import com.sun.star.container.*; +import com.sun.star.beans.*; +import com.sun.star.form.*; +import com.sun.star.sdbc.*; + + +/**************************************************************************/ +/** A helper class for recursively locking control models which are bound + to a specific field +*/ + +class LockControlModels extends ComponentTreeTraversal +{ + private String m_sDataField; + private Boolean m_aLockIt; + private int m_nLevel; // nesting level relative to the form we started with + + /* ------------------------------------------------------------------ */ + public LockControlModels( String sDataField, boolean bLockIt ) + { + m_sDataField = sDataField; + m_aLockIt = Boolean.valueOf( bLockIt ); + m_nLevel = 0; + } + + /* ------------------------------------------------------------------ */ + @Override + protected boolean shouldStepInto( XIndexContainer xContainer ) + { + if ( !super.shouldStepInto( xContainer ) ) + return false; // don't try to be more clever than our base class + + XForm xForm = UnoRuntime.queryInterface( XForm.class, xContainer ); + if ( ( null != xForm ) && ( m_nLevel > 1 ) ) + // don't step into sub forms - we only handle the form we were originally + // applied to + return false; + + return true; + } + + /* ------------------------------------------------------------------ */ + @Override + public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception + { + // entering this nesting level + ++m_nLevel; + + // check if the component has a DataField property + XPropertySet xCompProps = UNO.queryPropertySet( aFormComponent ); + XPropertySetInfo xPSI = null; + if ( null != xCompProps ) + xPSI = xCompProps.getPropertySetInfo(); + + if ( ( null != xPSI ) && xPSI.hasPropertyByName( "DataField" ) ) + { // indeed it has... + String sDataField = (String)xCompProps.getPropertyValue( "DataField" ); + if ( sDataField.equals( m_sDataField ) ) + { // we found a control model which is bound to what we're looking for + xCompProps.setPropertyValue( "ReadOnly", m_aLockIt ); + } + } + + // allow the super class to step down, if possible + super.handle( aFormComponent ); + + // leaving this nesting level + --m_nLevel; + } +} + +/**************************************************************************/ +/** a class which automatically handles control locking. + <p>The class has to be bound to a form. Upon every movement of the form, + all controls which are bound to a (to be specified) field are locked + on existing and unlocked on new records.</p> +*/ +class ControlLock implements XRowSetListener +{ + private XPropertySet m_xForm; + private String m_sDataField; + private boolean m_bLockingEnabled; + private boolean m_bPreviousRoundLock; + + /* ------------------------------------------------------------------ */ + ControlLock( XPropertySet xForm, String sBoundDataField ) + { + m_xForm = xForm; + m_sDataField = sBoundDataField; + m_bLockingEnabled = false; + m_bPreviousRoundLock = false; + } + + /* ------------------------------------------------------------------ */ + /** updates the locks on the affected controls + */ + private void updateLocks( ) + { + try + { + // first determine if we need to lock + Boolean aIsNewRecord = (Boolean)m_xForm.getPropertyValue( "IsNew" ); + + boolean bNeedLock = m_bLockingEnabled && !aIsNewRecord.booleanValue(); + + if ( m_bPreviousRoundLock != bNeedLock ) + { + LockControlModels aLocker = new LockControlModels( m_sDataField, bNeedLock ); + aLocker.handle( m_xForm ); + m_bPreviousRoundLock = bNeedLock; + } + + // please note that we choose the expensive way here: We always loop through + // _all_ control models belonging to the form. This clearly slows down the + // whole process. + // A better solution would be to cache the affected control models. Then we + // could either rely on the fact that the model hierarchy is static, or we + // could add ourself as container listener to the form. + } + catch(com.sun.star.uno.Exception e) + { + System.out.println(e); + e.printStackTrace(); + } + } + + /* ------------------------------------------------------------------ */ + /** enables the locking in general + <p>If the control models are really locked depends on the current + record of the form: on the insert row, controls are never locked.</p> + */ + public void enableLock( boolean bLock ) + { + // remember this new setting + m_bLockingEnabled = bLock; + + // add or remove ourself as listener to get notified of cursor moves + XRowSet xRowSet = UnoRuntime.queryInterface( + XRowSet.class, m_xForm ); + if ( m_bLockingEnabled ) + { + xRowSet.addRowSetListener( this ); + } + else + { + xRowSet.removeRowSetListener( this ); + } + + // update the locks + updateLocks(); + } + + /* ================================================================== + = UNO callbacks + ================================================================== */ + + /* ------------------------------------------------------------------ */ + // XResetListener overridables + /* ------------------------------------------------------------------ */ + public void cursorMoved( EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + updateLocks( ); + } + + /* ------------------------------------------------------------------ */ + public void rowChanged( EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + // not interested in + } + + /* ------------------------------------------------------------------ */ + public void rowSetChanged( EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + // not interested in + } + + /* ------------------------------------------------------------------ */ + // XEventListener overridables + /* ------------------------------------------------------------------ */ + public void disposing( EventObject aEvent ) + { + // not interested in + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/ControlValidation.java b/odk/examples/DevelopersGuide/Forms/ControlValidation.java new file mode 100644 index 000000000..4b176a371 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/ControlValidation.java @@ -0,0 +1,85 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +import com.sun.star.beans.*; + +public class ControlValidation extends DocumentBasedExample +{ + /** Creates a new instance of ControlValidation */ + public ControlValidation() + { + super( DocumentType.WRITER ); + } + + /* ------------------------------------------------------------------ */ + /* public test methods */ + /* ------------------------------------------------------------------ */ + @Override + protected void prepareDocument() throws com.sun.star.uno.Exception, java.lang.Exception + { + super.prepareDocument(); + + SingleControlValidation validation; + XPropertySet focusField; + + validation = new SingleControlValidation( m_document, 5, 5, "DatabaseFormattedField", new NumericValidator() ); + focusField = validation.getInputField(); + validation.setExplanatoryText( "Please enter a number between 0 and 100, with at most 1 decimal digit" ); + + validation = new SingleControlValidation( m_document, 90, 5, "DatabaseTextField", new TextValidator() ); + validation.setExplanatoryText( "Please enter a text whose length is a multiple of 3, and which does not contain the letter 'Z'" ); + + validation = new SingleControlValidation( m_document, 5, 55, "DatabaseDateField", new DateValidator() ); + validation.setExplanatoryText( "Please enter a date in the current month" ); + validation.getInputField().setPropertyValue( "Dropdown", Boolean.TRUE ); + + validation = new SingleControlValidation( m_document, 90, 55, "DatabaseTimeField", new TimeValidator() ); + validation.setExplanatoryText( "Please enter a time. Valid values are all full hours." ); + + validation = new SingleControlValidation( m_document, 5, 110, "DatabaseCheckBox", new BooleanValidator( false ) ); + validation.setExplanatoryText( "Please check (well, or uncheck) the box. Don't leave it in indetermined state." ); + validation.getInputField().setPropertyValue( "TriState", Boolean.TRUE ); + + validation = new SingleControlValidation( m_document, 90, 110, "DatabaseRadioButton", new BooleanValidator( true ), 3, 0 ); + validation.setExplanatoryText( "Please check any but the first button" ); + + validation = new SingleControlValidation( m_document, 5, 165, "DatabaseListBox", new ListSelectionValidator( ), 1, 24 ); + validation.setExplanatoryText( "Please select not more than two entries." ); + validation.getInputField().setPropertyValue( "MultiSelection", Boolean.TRUE ); + validation.getInputField().setPropertyValue( "StringItemList", new String[] { "first", "second", "third", "forth", "fivth" } ); + + // switch to alive mode + m_document.getCurrentView( ).toggleFormDesignMode( ); + m_document.getCurrentView( ).grabControlFocus( focusField ); + + // wait for the user telling us to exit + waitForUserInput(); + } + + /* ------------------------------------------------------------------ */ + /** class entry point + */ + public static void main(String argv[]) throws java.lang.Exception + { + ControlValidation aSample = new ControlValidation(); + aSample.run( argv ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/ControlValidator.java b/odk/examples/DevelopersGuide/Forms/ControlValidator.java new file mode 100644 index 000000000..c29dec558 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/ControlValidator.java @@ -0,0 +1,52 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// base class for components validating the content of form controls + +public abstract class ControlValidator implements com.sun.star.form.validation.XValidator +{ + + /** Creates a new instance of ControlValidator */ + public ControlValidator() + { + } + + public void addValidityConstraintListener(com.sun.star.form.validation.XValidityConstraintListener xValidityConstraintListener) + { + } + + public void removeValidityConstraintListener(com.sun.star.form.validation.XValidityConstraintListener xValidityConstraintListener) + { + } + + protected boolean isVoid( Object Value ) + { + try + { + return ( com.sun.star.uno.AnyConverter.getType(Value).getTypeClass() + == com.sun.star.uno.TypeClass.VOID ); + } + catch( java.lang.ClassCastException e ) + { + } + return false; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/DataAwareness.java b/odk/examples/DevelopersGuide/Forms/DataAwareness.java new file mode 100644 index 000000000..fbb3b7fe5 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/DataAwareness.java @@ -0,0 +1,940 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ +import com.sun.star.beans.PropertyChangeEvent; +import com.sun.star.beans.XPropertyChangeListener; +import com.sun.star.beans.XPropertySet; + + +// __________ Imports __________ +import com.sun.star.beans.XPropertySetInfo; + +// base classes +import com.sun.star.container.XIndexContainer; +import com.sun.star.container.XNameAccess; +import com.sun.star.container.XNamed; +import com.sun.star.form.FormComponentType; +import com.sun.star.form.ListSourceType; +import com.sun.star.form.XGridColumnFactory; +import com.sun.star.form.XReset; +import com.sun.star.form.XResetListener; +import com.sun.star.form.runtime.FormFeature; +import com.sun.star.lang.EventObject; +import com.sun.star.lang.XComponent; +import com.sun.star.sdb.CommandType; +import com.sun.star.sdb.XColumnUpdate; +import com.sun.star.sdbc.ResultSetConcurrency; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbc.XDataSource; +import com.sun.star.sdbc.XStatement; +import com.sun.star.sdbcx.XColumnsSupplier; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; + +/**************************************************************************/ +/** a class for enumerating a form component tree +*/ +class PrintComponentTree extends ComponentTreeTraversal +{ + private String m_sPrefix; + + public PrintComponentTree() + { + m_sPrefix = ""; + } + + @Override + public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception + { + // the name of the child + XNamed xName = UnoRuntime.queryInterface( XNamed.class, aFormComponent ); + + // if it's a form control model, check it's type + XPropertySet xProps = UNO.queryPropertySet( aFormComponent ); + String sTypeName = FLTools.classifyFormComponentType( xProps ); + + String sName; + if ( null == xName ) + sName = "<unnamed>"; + else + sName = xName.getName(); + + // print the component's name + if ( 0 != sTypeName.length() ) + { + System.out.println( m_sPrefix + sName + " (" + sTypeName + ")" ); + } + else + { + System.out.println( m_sPrefix + sName ); + } + + // let the super class step down the tree + m_sPrefix = m_sPrefix + " "; + super.handle( aFormComponent ); + m_sPrefix = m_sPrefix.substring( 0, m_sPrefix.length() - 1 ); + } +} + +/**************************************************************************/ +/** a class revoking button models from a ButtonOperator instance +*/ +class RevokeButtons extends ComponentTreeTraversal +{ + private ButtonOperator m_aOperator; + + public RevokeButtons( ButtonOperator aOperator ) + { + m_aOperator = aOperator; + } + + @Override + public void handle( Object aFormComponent ) throws com.sun.star.uno.Exception + { + // check if it's a button + XPropertySet xProps = UNO.queryPropertySet( aFormComponent ); + XPropertySetInfo xPI = null; + if ( null != xProps ) + xPI = xProps.getPropertySetInfo(); + if ( ( null != xPI ) && xPI.hasPropertyByName( "ClassId" ) ) + { + Short nClassId = (Short)xProps.getPropertyValue( "ClassId" ); + if ( FormComponentType.COMMANDBUTTON == nClassId.shortValue() ) + { + // yes, it is + m_aOperator.revokeButton( xProps ); + } + } + + // let the super class step down the tree (if possible) + super.handle( aFormComponent ); + } +} + +/**************************************************************************/ +public class DataAwareness extends DocumentBasedExample implements XPropertyChangeListener, XResetListener +{ + /* ================================================================== */ + private HsqlDatabase m_database; + + private static final String s_tableNameSalesmen = "SALESMEN"; + private static final String s_tableNameCustomers = "CUSTOMERS"; + private static final String s_tableNameSales = "SALES"; + + private XPropertySet m_xMasterForm; + private ButtonOperator m_aOperator; + + private KeyGenerator m_aSalesmanKeyGenerator; + private KeyGenerator m_aSalesKeyGenerator; + private ControlLock m_aSalesmenLocker; + private ControlLock m_aSalesLocker; + private GridFieldValidator m_aSalesNameValidator; + + private boolean m_bDefaultSalesDate; + private boolean m_bProtectKeyFields; + private boolean m_bAllowEmptySales; + + /* ------------------------------------------------------------------ */ + public DataAwareness() + { + super( DocumentType.WRITER ); + m_bDefaultSalesDate = false; + m_bProtectKeyFields = false; + m_bAllowEmptySales = false; + } + + /* ================================================================== + = form components + ================================================================== */ + + /* ------------------------------------------------------------------ */ + /** enumerates and prints all the elements in the given container, together with the container itself + */ + protected void enumFormComponents( XNameAccess xContainer ) throws java.lang.Exception + { + String sObjectName; + + XNamed xNameAcc = UnoRuntime.queryInterface( XNamed.class, xContainer ); + if ( null == xNameAcc ) + sObjectName = "<unnamed>"; + else + sObjectName = xNameAcc.getName(); + System.out.println( "enumerating the container named \"" + sObjectName + + "\"\n" ); + + PrintComponentTree aPrinter = new PrintComponentTree(); + aPrinter.handle( xContainer ); + } + + /* ------------------------------------------------------------------ */ + /** enumerates and prints all form elements in the document + */ + protected void enumFormComponents( ) throws java.lang.Exception + { + enumFormComponents( m_document.getFormComponentTreeRoot() ); + } + + /* ================================================================== + = UNO callbacks + ================================================================== */ + + /* ------------------------------------------------------------------ */ + // XResetListener overridables + /* ------------------------------------------------------------------ */ + public boolean approveReset( EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + // not interested in vetoing this + return true; + } + + /* ------------------------------------------------------------------ */ + public void resetted( EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + // check if this reset occurred because we're on a new record + XPropertySet xFormProps = UNO.queryPropertySet( aEvent.Source ); + try + { + Boolean aIsNew = (Boolean)xFormProps.getPropertyValue( "IsNew" ); + if ( aIsNew.booleanValue() ) + { // yepp + + if ( !m_bDefaultSalesDate ) + { // we're interested to do all this only if the user told us to default the sales date + // to "today" + // As date fields do this defaulting automatically, the semantics is inverted here: + // If we're told to default, we must do nothing, if we should not default, we must + // reset the value which the date field set automatically. + + Integer aConcurrency = (Integer)xFormProps.getPropertyValue( "ResultSetConcurrency" ); + if ( ResultSetConcurrency.READ_ONLY != aConcurrency.intValue() ) + { + // we're going to modify the record, though after that, to the user, it should look + // like it has not been modified + // So we need to ensure that we do not change the IsModified property with whatever we do + Object aModifiedFlag = xFormProps.getPropertyValue( "IsModified" ); + + + // get the columns of our master form + XColumnsSupplier xSuppCols = UnoRuntime.queryInterface( + XColumnsSupplier.class, xFormProps ); + XNameAccess xCols = xSuppCols.getColumns(); + + // and update the date column with a NULL value + XColumnUpdate xDateColumn = UnoRuntime.queryInterface( + XColumnUpdate.class, xCols.getByName( "SALEDATE" ) ); + xDateColumn.updateNull(); + + + // then restore the flag + xFormProps.setPropertyValue( "IsModified", aModifiedFlag ); + } + } + } + } + catch( com.sun.star.uno.Exception e ) + { + System.out.println(e); + e.printStackTrace(); + } + } + + /* ------------------------------------------------------------------ */ + // XPropertyChangeListener overridables + /* ------------------------------------------------------------------ */ + public void propertyChange( PropertyChangeEvent aEvent ) throws com.sun.star.uno.RuntimeException + { + try + { + // did it come from a radio button or checkbox? + if ( aEvent.PropertyName.equals( "State" ) ) + { // yep + Short aNewState = (Short)aEvent.NewValue; + + XPropertySet xModel = UNO.queryPropertySet( aEvent.Source ); + String sName = (String)xModel.getPropertyValue( "Name" ); + + Short aClassId = (Short)xModel.getPropertyValue( "ClassId" ); + if ( FormComponentType.RADIOBUTTON == aClassId.shortValue() ) + { + String sRefValue = (String)xModel.getPropertyValue( "RefValue" ); + + short nNewValue = ((Short)aEvent.NewValue).shortValue(); + if ( sName.equals( "KeyGen" ) ) + { + // it's one of the options for key generation + if ( sRefValue.equals( "none" ) ) + { // no automatic generation at all + m_aSalesmanKeyGenerator.stopGenerator( ); + m_aSalesKeyGenerator.stopGenerator( ); + } + else + { + boolean bGenerateOnReset = true; + if ( sRefValue.equals( "update" ) ) + { // generate on update + bGenerateOnReset = ( 0 == nNewValue ); + } + else if ( sRefValue.equals( "reset" ) ) + { // generate on reset + bGenerateOnReset = ( 0 != nNewValue ); + } + m_aSalesmanKeyGenerator.activateKeyGenerator( bGenerateOnReset ); + m_aSalesKeyGenerator.activateKeyGenerator( bGenerateOnReset ); + } + } + } + else if ( FormComponentType.CHECKBOX == aClassId.shortValue() ) + { + boolean bEnabled = ( 0 != aNewState.shortValue() ); + if ( sName.equals( "defaultdate" ) ) + { + m_bDefaultSalesDate = bEnabled; + } + else if ( sName.equals( "protectkeys" ) ) + { + m_bProtectKeyFields = bEnabled; + m_aSalesmenLocker.enableLock( m_bProtectKeyFields ); + m_aSalesLocker.enableLock( m_bProtectKeyFields ); + } + else if ( sName.equals( "emptysales" ) ) + { + m_bAllowEmptySales = bEnabled; + m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales ); + } + } + } + } + catch(com.sun.star.uno.Exception e) + { + System.out.println(e); + e.printStackTrace(); + } + } + + /* ------------------------------------------------------------------ */ + // XEventListener overridables + /* ------------------------------------------------------------------ */ + @Override + public void disposing( EventObject aEvent ) + { + // simply disambiguate + super.disposing( aEvent ); + } + + /* ================================================================== + = miscellaneous + ================================================================== */ + + /* ------------------------------------------------------------------ */ + /** skips line feeds in the input stream + + @returns + the first character which does not belong to a line feed + */ + protected int skipLineFeeds( java.io.InputStream aInput ) throws java.io.IOException + { + // read characters, until we encounter something which is not a line feed character + int nChar = aInput.read( ); + while ( ( 13 == nChar ) || ( 10 == nChar ) ) + nChar = aInput.read( ); + + // now read everything which is behind this single character we are interested in + while ( 0 < aInput.available() ) + aInput.read( ); + + return nChar; + } + + /* ================================================================== + = table handling + ================================================================== */ + /* ------------------------------------------------------------------ */ + /** checks if a given table exists. + + <p>The check is made using a SELECT statement, so even if the connection + is a n SDB-level connection, which may filter tables in its table + supplier, the result may be reliable...</p> + */ + protected boolean existsInvisibleTable( XConnection xConn, String sTableName ) throws java.lang.Exception + { + String sStatement = "SELECT * FROM "; + sStatement += sTableName; + sStatement += " WHERE 0=1"; + + boolean bSuccess = false; + try + { + XStatement xStatement = xConn.createStatement(); + xStatement.execute( sStatement ); + // if we reached this point, the table probably exists + bSuccess = true; + } + catch(com.sun.star.sdbc.SQLException e) + { + } + return bSuccess; + } + + /* ------------------------------------------------------------------ */ + /** add a specified table name to the table filter of the given data source. + */ + protected void makeTableVisible( XDataSource xDS, String sTableName ) throws java.lang.Exception + { + // get the table filter + XPropertySet xDSP = UNO.queryPropertySet( xDS ); + String[] aCurrentFilter = (String[])xDSP.getPropertyValue( "TableFilter" ); + + // check if the table name is already part of it + String sAllTables = "*"; // all tables + + for ( int i=0; i<aCurrentFilter.length; ++i ) + { + String sCurrentTableFilter = aCurrentFilter[i]; + + if ( sCurrentTableFilter.equals( sTableName ) ) + return; + if ( sCurrentTableFilter.equals( sAllTables ) ) + return; + } + + // if we are here, we have to add our table to the filter sequence + String[] aNewFilter = new String[ aCurrentFilter.length + 1 ]; + // copy the existent filter entries + for ( int i=0; i<aCurrentFilter.length; ++i ) + aNewFilter[i] = aCurrentFilter[i]; + // add our table + aNewFilter[ aCurrentFilter.length ] = sTableName; + + xDSP.setPropertyValue( "TableFilter", aNewFilter ); + } + + /* ------------------------------------------------------------------ */ + /** executes the given statement on the given connection + */ + protected boolean implExecuteStatement( XConnection xConn, String sStatement ) throws java.lang.Exception + { + try + { + XStatement xStatement = xConn.createStatement( ); + xStatement.execute( sStatement ); + } + catch(com.sun.star.sdbc.SQLException e) + { + System.err.println( e ); + return false; + } + + return true; + } + + /* ------------------------------------------------------------------ */ + /** creates the table with the given name, using the given statement + */ + protected boolean implCreateTable( XConnection xConn, String sCreateStatement, String sTableName ) throws java.lang.Exception + { + if ( !implExecuteStatement( xConn, sCreateStatement ) ) + { + System.out.println( " could not create the table " + sTableName + "." ); + System.out.println( ); + return false; + } + + return true; + } + + /* ------------------------------------------------------------------ */ + /** creates the table SALESMEN + + @return + <TRUE/> if and only if the creation succeeded + */ + protected boolean createTableSalesman( XConnection xConn ) throws java.lang.Exception + { + String sCreateStatement = "CREATE TABLE " + s_tableNameSalesmen + " "; + sCreateStatement += "(SNR INTEGER NOT NULL, "; + sCreateStatement += "FIRSTNAME VARCHAR(50), "; + sCreateStatement += "LASTNAME VARCHAR(100), "; + sCreateStatement += "STREET VARCHAR(50), "; + sCreateStatement += "STATE VARCHAR(50), "; + sCreateStatement += "ZIP INTEGER, "; + sCreateStatement += "BIRTHDATE DATE, "; + sCreateStatement += "PRIMARY KEY(SNR))"; + + if ( implCreateTable( xConn, sCreateStatement, s_tableNameSalesmen) ) + { + String sInsertionPrefix = "INSERT INTO " + s_tableNameSalesmen + " VALUES "; + + implExecuteStatement( xConn, sInsertionPrefix + "(1, 'Joseph', 'Smith', 'Bond Street', 'CA', 95460, '1946-07-02')" ); + implExecuteStatement( xConn, sInsertionPrefix + "(2, 'Frank', 'Jones', 'Lake silver', 'CA', 95460, '1963-12-24')" ); + implExecuteStatement( xConn, sInsertionPrefix + "(3, 'Jane', 'Esperansa', '23 Hollywood driver', 'CA', 95460, '1972-04-01')" ); + + return true; + } + return false; + } + + /* ------------------------------------------------------------------ */ + /** creates the table CUSTOMERS + + @return + <TRUE/> if and only if the creation succeeded + */ + protected boolean createTableCustomer( XConnection xConn ) throws java.lang.Exception + { + String sCreateStatement = "CREATE TABLE " + s_tableNameCustomers + " "; + sCreateStatement += "(COS_NR INTEGER NOT NULL, "; + sCreateStatement += "LASTNAME VARCHAR(100), "; + sCreateStatement += "STREET VARCHAR(50), "; + sCreateStatement += "CITY VARCHAR(50), "; + sCreateStatement += "STATE VARCHAR(50), "; + sCreateStatement += "ZIP INTEGER, "; + sCreateStatement += "PRIMARY KEY(COS_NR))"; + + if ( implCreateTable( xConn, sCreateStatement, s_tableNameCustomers ) ) + { + String sInsertionPrefix = "INSERT INTO " + s_tableNameCustomers + " VALUES "; + + implExecuteStatement( xConn, sInsertionPrefix + "(100, 'Acme, Inc.', '99 Market Street', 'Groundsville', 'CA', 95199)" ); + implExecuteStatement( xConn, sInsertionPrefix + "(101, 'Superior BugSoft', '1 Party Place', 'Mendocino', 'CA', 95460)"); + implExecuteStatement( xConn, sInsertionPrefix + "(102, 'WeKnowAll, Inc.', '100 Coffee Lane', 'Meadows', 'CA', 93699)"); + + return true; + } + return false; + } + + /* ------------------------------------------------------------------ */ + /** creates the table SALES + + @return + <TRUE/> if and only if the creation succeeded + */ + protected boolean createTableSales( XConnection xConn ) throws java.lang.Exception + { + String sCreateStatement = "CREATE TABLE " + s_tableNameSales + " "; + sCreateStatement += "(SALENR INTEGER NOT NULL, "; + sCreateStatement += "COS_NR INTEGER NOT NULL, "; + sCreateStatement += "SNR INTEGER NOT NULL, "; + sCreateStatement += "NAME VARCHAR(50), "; + sCreateStatement += "SALEDATE DATE, "; + sCreateStatement += "PRICE DECIMAL(8,2), "; + sCreateStatement += "PRIMARY KEY(SALENR))"; + + if ( implCreateTable( xConn, sCreateStatement, s_tableNameSales ) ) + { + String sInsertionPrefix = "INSERT INTO " + s_tableNameSales + " VALUES "; + + implExecuteStatement( xConn, sInsertionPrefix + "(1, 100, 1, 'Fruits', '2005-02-12', 39.99)" ); + implExecuteStatement( xConn, sInsertionPrefix + "(2, 101, 3, 'Beef', '2005-10-18', 15.78)" ); + implExecuteStatement( xConn, sInsertionPrefix + "(3, 102, 3, 'Orange Juice', '2005-09-08', 25.63)" ); + implExecuteStatement( xConn, sInsertionPrefix + "(4, 101, 2, 'Oil', '2005-03-01', 12.30)" ); + + return true; + } + + return false; + } + + /* ------------------------------------------------------------------ */ + /** ensures that the tables we need for our example exist + */ + protected void ensureTables() throws java.lang.Exception + { + // get the data source + XDataSource xDS = m_database.getDataSource(); + XPropertySet xDSProps = UNO.queryPropertySet( xDS ); + + // connect to this data source + XConnection xConn = xDS.getConnection( "", "" ); + XComponent xConnComp = UNO.queryComponent( xConn ); + + createTableSalesman( xConn ); + createTableCustomer( xConn ); + createTableSales( xConn ); + + // free the resources acquired by the connection + xConnComp.dispose(); + } + + /* ================================================================== + = sample document handling + ================================================================== */ + + /* ------------------------------------------------------------------ */ + /** creates the button used for demonstrating (amongst others) event handling + @param nXPos + x-position of the to be inserted shape + @param nYPos + y-position of the to be inserted shape + @param nXSize + width of the to be inserted shape + @param sName + the name of the model in the form component hierarchy + @param sLabel + the label of the button control + @param sActionURL + the URL of the action which should be triggered by the button + @return + the model of the newly created button + */ + protected XPropertySet createButton( int nXPos, int nYPos, int nXSize, String sName, String sLabel, short _formFeature ) throws java.lang.Exception + { + XPropertySet xButton = m_formLayer.createControlAndShape( "CommandButton", nXPos, nYPos, nXSize, 6 ); + // the name for referring to it later: + xButton.setPropertyValue( "Name", sName ); + // the label + xButton.setPropertyValue( "Label", sLabel ); + // use the name as help text + xButton.setPropertyValue( "HelpText", sName ); + // don't want buttons to be accessible by the "tab" key - this would be uncomfortable when traveling + // with records with "tab" + xButton.setPropertyValue( "Tabstop", Boolean.FALSE ); + // similar, they should not steal the focus when clicked + xButton.setPropertyValue( "FocusOnClick", Boolean.FALSE ); + + m_aOperator.addButton( xButton, _formFeature ); + + return xButton; + } + + /* ------------------------------------------------------------------ */ + /** creates a column in a grid + @param xGridModel + specifies the model of the grid where the new column should be inserted + @param sColumnService + specifies the service name of the column to create (e.g. "NumericField") + @param sDataField + specifies the database field to which the column should be bound + @param nWidth + specifies the column width (in mm). If 0, no width is set. + @return + the newly created column + */ + XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField, int nWidth ) + throws com.sun.star.uno.Exception + { + // the container to insert columns into + XIndexContainer xColumnContainer = UNO.queryIndexContainer( aGridModel ); + // the factory for creating column models + XGridColumnFactory xColumnFactory = UnoRuntime.queryInterface( + XGridColumnFactory.class, aGridModel ); + + // (let) create the new col + XInterface xNewCol = xColumnFactory.createColumn( sColumnService ); + XPropertySet xColProps = UNO.queryPropertySet( xNewCol ); + + // some props + // the field the column is bound to + xColProps.setPropertyValue( "DataField", sDataField ); + // the "display name" of the column + xColProps.setPropertyValue( "Label", sDataField ); + // the name of the column within its parent + xColProps.setPropertyValue( "Name", sDataField ); + + if ( nWidth > 0 ) + xColProps.setPropertyValue( "Width", Integer.valueOf( nWidth * 10 ) ); + + // insert + xColumnContainer.insertByIndex( xColumnContainer.getCount(), xNewCol ); + + // outta here + return xColProps; + } + + /* ------------------------------------------------------------------ */ + /** creates a column in a grid + */ + XPropertySet createGridColumn( Object aGridModel, String sColumnService, String sDataField ) + throws com.sun.star.uno.Exception + { + return createGridColumn( aGridModel, sColumnService, sDataField ); + } + + /* ------------------------------------------------------------------ */ + /** creates our sample document + */ + @Override + protected void prepareDocument() throws com.sun.star.uno.Exception, java.lang.Exception + { + super.prepareDocument(); + + m_database = new HsqlDatabase( m_xCtx ); + + // ensure that we have the tables needed for our example + ensureTables(); + + + /* create some shapes */ + XPropertySet xSNRField = m_formLayer.insertControlLine( "NumericField", "SNR", "", 3 ); + m_formLayer.insertControlLine( "TextField", "FIRSTNAME", "", 11); + m_formLayer.insertControlLine( "TextField", "LASTNAME", "", 19 ); + m_formLayer.insertControlLine( "TextField", "STREET", "", 27 ); + m_formLayer.insertControlLine( "TextField", "STATE", "", 35 ); + XPropertySet xZipField = m_formLayer.insertControlLine( "NumericField", "ZIP", "", 43 ); + m_formLayer.insertControlLine( "FormattedField", "BIRTHDATE", "", 51 ); + + // for the salesman number / zip code, we don't want to have decimal places: + xSNRField.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) ); + xZipField.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) ); + + + /** need the form the control models belong to + for this, we simply obtain the parent for any of the control models we have + + Note that this involves knowledge about the implementation: If a control shape is + inserted into a document, where the control model does not belong to the form component + hierarchy, yet, it is automatically inserted into the first form, which is created + if necessary. + */ + m_xMasterForm = FLTools.getParent( xZipField ); + + // set the data source signature at the form + m_xMasterForm.setPropertyValue( "DataSourceName", m_database.getDocumentURL() ); + m_xMasterForm.setPropertyValue( "CommandType", Integer.valueOf( CommandType.TABLE ) ); + m_xMasterForm.setPropertyValue( "Command", "SALESMEN" ); + + + // insert the buttons + // create our button operator, if necessary + m_aOperator = new ButtonOperator( m_xCtx, m_document, m_xMasterForm ); + + createButton( 2, 63, 8, "first", "<<", FormFeature.MoveToFirst ); + createButton( 12, 63, 8, "prev", "<", FormFeature.MoveToPrevious ); + createButton( 22, 63, 8, "next", ">", FormFeature.MoveToNext ); + createButton( 32, 63, 8, "last", ">>", FormFeature.MoveToLast ); + createButton( 42, 63, 8, "new", ">*", FormFeature.MoveToInsertRow ); + createButton( 58, 63, 13, "reload", "reload", FormFeature.ReloadForm ); + + + // create a sub form for the sales + + // for this, first create a sub form and bind it to the SALES table + XIndexContainer xSalesForm = m_document.createSubForm( m_xMasterForm, "Sales" ); + XPropertySet xSalesFormProps = UNO.queryPropertySet( xSalesForm ); + + xSalesFormProps.setPropertyValue( "DataSourceName", m_database.getDocumentURL() ); + xSalesFormProps.setPropertyValue( "CommandType", Integer.valueOf( CommandType.COMMAND ) ); + + String sCommand = "SELECT * FROM "; + sCommand += s_tableNameSales; + sCommand += " WHERE " + s_tableNameSales + ".SNR = :salesmen"; + xSalesFormProps.setPropertyValue( "Command", sCommand ); + + // the master-details connection + String[] aMasterFields = new String[] { "SNR" }; // the field in the master form + String[] aDetailFields = new String[] { "salesmen" }; // the name in the detail form + xSalesFormProps.setPropertyValue( "MasterFields", aMasterFields ); + xSalesFormProps.setPropertyValue( "DetailFields", aDetailFields ); + + // the create thr grid model + XPropertySet xSalesGridModel = m_formLayer.createControlAndShape( "GridControl", 2, 80, 162, 40, xSalesForm ); + xSalesGridModel.setPropertyValue( "Name", "SalesTable" ); + XPropertySet xKeyColumn = createGridColumn( xSalesGridModel, "NumericField", "SALENR", 12 ); + XPropertySet xCustomerColumn = createGridColumn( xSalesGridModel, "ListBox", "COS_NR", 40 ); + XPropertySet xSalesNameColumn = createGridColumn( xSalesGridModel, "TextField", "NAME", 25 ); + createGridColumn( xSalesGridModel, "DateField", "SALEDATE", 24 ); + createGridColumn( xSalesGridModel, "CurrencyField", "PRICE", 16 ); + + // please note that a better solution for the SALEDATE field would have been to use + // a FormattedField. But we want to demonstrate some effects with DateFields here ... + + m_aSalesNameValidator = new GridFieldValidator( m_xCtx, xSalesNameColumn ); + m_aSalesNameValidator.enableColumnWatch( m_bAllowEmptySales ); + + xKeyColumn.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) ); + + // init the list box which is for choosing the customer a sale belongs to + xCustomerColumn.setPropertyValue( "BoundColumn", Short.valueOf( (short)1 ) ); + xCustomerColumn.setPropertyValue( "Label", "Customer" ); + xCustomerColumn.setPropertyValue( "ListSourceType", ListSourceType.SQL ); + + String sListSource = "SELECT LASTNAME, COS_NR FROM "; + sListSource += s_tableNameCustomers; + String[] aListSource = new String[] { sListSource }; + xCustomerColumn.setPropertyValue( "ListSource", aListSource ); + + // We want to demonstrate how to reset fields to NULL, we do this with the SALEDATE field + // above. For this, we add as reset listener to the form + XReset xFormReset = UNO.queryReset( xSalesForm ); + xFormReset.addResetListener( this ); + + + + // the option for filtering the sales form + XIndexContainer xSalesFilterForm = m_document.createSiblingForm( xSalesForm, "SalesFilter" ); + XPropertySet xSFFProps = UNO.queryPropertySet( xSalesFilterForm ); + XPropertySet xLabel = m_formLayer.createControlAndShape( "FixedText", 2, 125, 35, 6, xSalesFilterForm ); + xLabel.setPropertyValue( "Label", "show only sales since" ); + xLabel.setPropertyValue( "Name", "FilterLabel" ); + + XPropertySet xFilterSelection = m_formLayer.createControlAndShape( "ListBox", 40, 125, 59, 6, xSalesFilterForm ); + xFilterSelection.setPropertyValue( "Name", "FilterList" ); + xFilterSelection.setPropertyValue( "LabelControl", xLabel ); + XPropertySet xManualFilter = m_formLayer.createControlAndShape( "DateField", 104, 125, 30, 6, xSalesFilterForm ); + xManualFilter.setPropertyValue( "Name", "ManualFilter" ); + XPropertySet xApplyFilter = m_formLayer.createControlAndShape( "CommandButton", 139, 125, 25, 6, xSalesFilterForm ); + xApplyFilter.setPropertyValue( "Name", "ApplyFilter" ); + xApplyFilter.setPropertyValue( "DefaultButton", Boolean.TRUE ); + new SalesFilter( m_document, xSalesFormProps, xFilterSelection, + xManualFilter, xApplyFilter ); + + + + // the options section + // for this, we need a form which is a sibling of our master form (don't want to interfere + // the controls which represent options only with the controls which are used for data access) + + XIndexContainer xOptionsForm = m_document.createSiblingForm( m_xMasterForm, "Options" ); + + xLabel = m_formLayer.createControlAndShape( "GroupBox", 98, 0, 66, 62, xOptionsForm ); + xLabel.setPropertyValue( "Name", "Options" ); + xLabel.setPropertyValue( "Label", "Options" ); + + // radio buttons which controls how we generate unique keys + xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 5, 56, 25, xOptionsForm ); + xLabel.setPropertyValue( "Label", "key generation" ); + xLabel.setPropertyValue( "Name", "KeyGeneration" ); + XPropertySet xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 11, 50, 6, xOptionsForm ); + xKeyGen.setPropertyValue( "Name", "KeyGen" ); + xKeyGen.setPropertyValue( "Label", "no automatic generation" ); + xKeyGen.setPropertyValue( "RefValue", "none" ); + xKeyGen.addPropertyChangeListener( "State", this ); + + xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 17, 50, 6, xOptionsForm ); + xKeyGen.setPropertyValue( "Name", "KeyGen" ); + xKeyGen.setPropertyValue( "Label", "before inserting a record" ); + xKeyGen.setPropertyValue( "RefValue", "update" ); + xKeyGen.addPropertyChangeListener( "State", this ); + + xKeyGen = m_formLayer.createControlAndShape( "RadioButton", 106, 23, 50, 6, xOptionsForm ); + xKeyGen.setPropertyValue( "Name", "KeyGen" ); + xKeyGen.setPropertyValue( "Label", "when moving to a new record" ); + xKeyGen.setPropertyValue( "RefValue", "reset" ); + xKeyGen.addPropertyChangeListener( "State", this ); + + // initialize listeners + // master form - key generation + m_aSalesmanKeyGenerator = new KeyGenerator( m_xMasterForm, "SNR", m_xCtx ); + m_aSalesmanKeyGenerator.activateKeyGenerator( true ); + // master form - control locking + m_aSalesmenLocker = new ControlLock( m_xMasterForm, "SNR" ); + m_aSalesmenLocker.enableLock( m_bProtectKeyFields ); + + // details form - key generation + m_aSalesKeyGenerator = new KeyGenerator( xSalesFormProps, "SALENR", m_xCtx ); + m_aSalesKeyGenerator.activateKeyGenerator( true ); + + // details form - control locking + m_aSalesLocker = new ControlLock( xSalesFormProps, "SALENR" ); + m_aSalesLocker.enableLock( m_bProtectKeyFields ); + + // initially, we want to generate keys when moving to a new record + xKeyGen.setPropertyValue( "DefaultState", Short.valueOf( (short)1 ) ); + + + // second options block + xLabel = m_formLayer.createControlAndShape( "GroupBox", 103, 33, 56, 25, xOptionsForm ); + xLabel.setPropertyValue( "Name", "Misc" ); + xLabel.setPropertyValue( "Label", "Miscellaneous" ); + + XPropertySet xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 39, 60, 6, xOptionsForm ); + xCheck.setPropertyValue( "Name", "defaultdate" ); + xCheck.setPropertyValue( "Label", "default sales date to \"today\"" ); + xCheck.setPropertyValue( "HelpText", "When checked, newly entered sales records are pre-filled with today's date, else left empty." ); + xCheck.addPropertyChangeListener( "State", this ); + + xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 45, 60, 6, xOptionsForm ); + xCheck.setPropertyValue( "Name", "protectkeys" ); + xCheck.setPropertyValue( "Label", "protect key fields from editing" ); + xCheck.setPropertyValue( "HelpText", "When checked, you cannot modify the values in the table's key fields (SNR and SALENR)" ); + xCheck.addPropertyChangeListener( "State", this ); + + xCheck = m_formLayer.createControlAndShape( "CheckBox", 106, 51, 60, 6, xOptionsForm ); + xCheck.setPropertyValue( "Name", "emptysales" ); + xCheck.setPropertyValue( "Label", "check for empty sales names" ); + xCheck.setPropertyValue( "HelpText", "When checked, you cannot enter empty values into the NAME column of the 'Sales' table." ); + xCheck.addPropertyChangeListener( "State", this ); + + // dump the form component tree + enumFormComponents( ); + } + + /* ------------------------------------------------------------------ */ + @Override + protected void onFormsAlive() + { + m_aOperator.onFormsAlive(); + } + + /* ------------------------------------------------------------------ */ + /** performs any cleanup before exiting the program + */ + @Override + protected void cleanUp( ) throws java.lang.Exception + { + // remove the listeners at the buttons + RevokeButtons aRevoke = new RevokeButtons( m_aOperator ); + aRevoke.handle( m_document.getFormComponentTreeRoot( ) ); + + // remove the key generator listeners from the form + m_aSalesmanKeyGenerator.stopGenerator( ); + m_aSalesKeyGenerator.stopGenerator( ); + + // and the control lockers + m_aSalesmenLocker.enableLock( false ); + m_aSalesLocker.enableLock( false ); + + // the validator for the grid column + m_aSalesNameValidator.enableColumnWatch( false ); + + // remove our own reset listener from the form + XNameAccess xMasterAsNames = UnoRuntime.queryInterface( + XNameAccess.class, m_xMasterForm ); + XReset xFormReset = UNO.queryReset( xMasterAsNames.getByName( "Sales" ) ); + xFormReset.removeResetListener( this ); + + super.cleanUp(); + } + + /* ------------------------------------------------------------------ */ + /** class entry point + */ + public static void main(String argv[]) throws java.lang.Exception + { + DataAwareness aSample = new DataAwareness(); + aSample.run( argv ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/DateValidator.java b/odk/examples/DevelopersGuide/Forms/DateValidator.java new file mode 100644 index 000000000..646dfac79 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/DateValidator.java @@ -0,0 +1,91 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +public class DateValidator extends ControlValidator +{ + + /** Creates a new instance of NumericValidator */ + public DateValidator( ) + { + } + + public String explainInvalid( Object Value ) + { + try + { + if ( isVoid( Value ) ) + return "empty input"; + + com.sun.star.util.Date dateValue = (com.sun.star.util.Date)Value; + if ( isDedicatedInvalidDate( dateValue ) ) + return "this is no valid date"; + + if ( !isNextMonthsDate( dateValue ) ) + return "date must denote a day in the current month"; + } + catch( java.lang.Exception e ) + { + return "oops. What did you enter for this to happen?"; + } + return ""; + } + + public boolean isValid( Object Value ) + { + try + { + if ( isVoid( Value ) ) + return false; + + com.sun.star.util.Date dateValue = (com.sun.star.util.Date) + com.sun.star.uno.AnyConverter.toObject( + com.sun.star.util.Date.class, Value); + if ( isDedicatedInvalidDate( dateValue ) ) + return false; + + if ( !isNextMonthsDate( dateValue ) ) + return false; + return true; + } + catch( java.lang.Exception e ) + { + e.printStackTrace( System.err ); + } + return false; + } + + private boolean isDedicatedInvalidDate( com.sun.star.util.Date dateValue ) + { + return ( dateValue.Day == 0 ) && ( dateValue.Month == 0 ) && ( dateValue.Year == 0 ); + } + + private boolean isNextMonthsDate( com.sun.star.util.Date dateValue ) + { + int overallMonth = dateValue.Year * 12 + dateValue.Month - 1; + + int todaysMonth = new java.util.Date().getMonth(); + int todaysYear = new java.util.Date().getYear() + 1900; + int todaysOverallMonth = todaysYear * 12 + todaysMonth; + + return overallMonth == todaysOverallMonth; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/DocumentBasedExample.java b/odk/examples/DevelopersGuide/Forms/DocumentBasedExample.java new file mode 100644 index 000000000..34735221f --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/DocumentBasedExample.java @@ -0,0 +1,219 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; +import com.sun.star.util.XCloseable; + +public abstract class DocumentBasedExample implements com.sun.star.lang.XEventListener +{ + /// the initial remote context from the office + protected XComponentContext m_xCtx; + /// our current test document + protected DocumentHelper m_document; + protected FormLayer m_formLayer; + private DocumentType m_documentType; + + /** Creates a new instance of DocumentBasedExample */ + public DocumentBasedExample( DocumentType documentType ) + { + bootstrapUNO(); + m_documentType = documentType; + } + + /* ------------------------------------------------------------------ */ + private void bootstrapUNO() + { + try + { + /* + final XComponentContext componentContext = com.sun.star.comp.helper.Bootstrap. + createInitialComponentContext( null ); + final XMultiComponentFactory localServiceManager = componentContext.getServiceManager(); + + final XUnoUrlResolver urlResolver = (XUnoUrlResolver) UnoRuntime.queryInterface( + XUnoUrlResolver.class, localServiceManager.createInstanceWithContext( + "com.sun.star.bridge.UnoUrlResolver", componentContext) ); + + final String connectStr = "uno:pipe,name=<pipename>;urp;StarOffice.ComponentContext"; + final Object initialObject = urlResolver.resolve( connectStr ); + + m_xCtx = (XComponentContext)UnoRuntime.queryInterface( XComponentContext.class, + initialObject ); + */ + + // get the remote office component context + m_xCtx = com.sun.star.comp.helper.Bootstrap.bootstrap(); + System.out.println("Connected to a running office ..."); + } + catch (java.lang.Exception e) + { + e.printStackTrace( System.err ); + System.exit(1); + } + } + + /* ------------------------------------------------------------------ */ + /** main method for running the sample + */ + public void run( String argv[] ) + { + try + { + // collect whatever parameters were given + collectParameters( argv ); + + // prepare our sample document + prepareDocument(); + + // switch the document view's form layer to alive mode + m_document.getCurrentView().toggleFormDesignMode(); + onFormsAlive(); + + // grab the focus to the first control + m_document.getCurrentView().grabControlFocus(); + + + // wait for the user to confirm that we can exit + if ( waitForUserInput() ) + { + // clean up + cleanUp(); + } + + // if waitForUserInput returns false, the user closed the document manually - no need to do a clean up + // then + } + catch(com.sun.star.uno.Exception e) + { + System.out.println(e); + e.printStackTrace(); + } + catch(java.lang.Exception e) + { + System.out.println(e); + e.printStackTrace(); + } + + System.exit(0); + } + + /* ------------------------------------------------------------------ */ + /** collect the RuntimeArguments + */ + private void collectParameters(String argv[]) + { + // not interested in. Derived classes may want to use it. + } + + /* ------------------------------------------------------------------ */ + /** prepares a new document to work with + */ + protected void prepareDocument() throws com.sun.star.uno.Exception, java.lang.Exception + { + m_document = DocumentHelper.blankDocument(m_xCtx, m_documentType); + m_document.getDocument( ).addEventListener( this ); + m_formLayer = new FormLayer( m_document ); + } + + /* ------------------------------------------------------------------ */ + /** called when the form layer has been switched to alive mode + */ + protected void onFormsAlive() + { + } + + /* ------------------------------------------------------------------ */ + /** performs any cleanup before exiting the program + */ + protected void cleanUp( ) throws java.lang.Exception + { + // do not listen at the document any longer + m_document.getDocument().removeEventListener( this ); + + // close the document + closeDocument(); + } + + /* ------------------------------------------------------------------ */ + /** closes our document, if we have an open one + */ + private void closeDocument() + { + try + { + // close our document + if ( m_document != null ) + { + XCloseable closeDoc = UnoRuntime.queryInterface( XCloseable.class, + m_document.getDocument() ); + if (closeDoc != null) + closeDoc.close( true ); + else + m_document.getDocument().dispose(); + } + } + catch ( com.sun.star.uno.Exception e ) + { + e.printStackTrace( System.err ); + } + } + + /* ------------------------------------------------------------------ */ + /* internal methods */ + /* ------------------------------------------------------------------ */ + /** waits for the user to press a key (on the console where she started + the java program) or the document to be closed by the user. + + @return <TRUE/> if the user pressed a key on the console, + <FALSE/> if she closed the document + */ + protected boolean waitForUserInput() throws java.lang.Exception + { + synchronized (this) + { + WaitForInput aWait = new WaitForInput( this ); + aWait.start(); + wait(); + + // if the waiter thread is done, the user pressed enter + boolean bKeyPressed = aWait.isDone(); + if ( !bKeyPressed ) + aWait.interrupt(); + + return bKeyPressed; + } + } + + /* ------------------------------------------------------------------ */ + /* XEventListener overridables */ + /* ------------------------------------------------------------------ */ + public void disposing( com.sun.star.lang.EventObject eventObject ) + { + if ( m_document.getDocument().equals( eventObject.Source ) ) + { + // notify ourself that we can stop waiting for user input + synchronized (this) + { + notify(); + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/DocumentHelper.java b/odk/examples/DevelopersGuide/Forms/DocumentHelper.java new file mode 100644 index 000000000..abfda37c4 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/DocumentHelper.java @@ -0,0 +1,306 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/**************************************************************************/ +import com.sun.star.uno.*; +import com.sun.star.lang.*; +import com.sun.star.drawing.*; +import com.sun.star.frame.*; +import com.sun.star.form.*; +import com.sun.star.beans.*; +import com.sun.star.container.*; + +/**************************************************************************/ +/** provides a small wrapper around a document +*/ +public class DocumentHelper +{ + /// the remote office context + private XComponentContext m_remoteContext; + /// the remote service manager + private XMultiServiceFactory m_orb; + protected XComponent m_documentComponent; + + /* ------------------------------------------------------------------ */ + public XComponent getDocument( ) + { + return m_documentComponent; + } + + /* ------------------------------------------------------------------ */ + public XComponentContext getContext( ) + { + return m_remoteContext; + } + + /* ------------------------------------------------------------------ */ + public XMultiServiceFactory getOrb( ) + { + return m_orb; + } + + /* ------------------------------------------------------------------ */ + public DocumentHelper( XComponentContext xContext, XComponent document ) + { + m_remoteContext = xContext; + m_orb = UnoRuntime.queryInterface( + XMultiServiceFactory.class, m_remoteContext.getServiceManager()); + m_documentComponent = document; + } + + /* ------------------------------------------------------------------ */ + protected static XComponent implCreateBlankDocument( XComponentContext xCtx, String factoryURL ) throws com.sun.star.uno.Exception + { + XComponentLoader aLoader = UnoRuntime.queryInterface( + XComponentLoader.class, + xCtx.getServiceManager().createInstanceWithContext( + "com.sun.star.frame.Desktop", xCtx )); + + return UNO.queryComponent( + aLoader.loadComponentFromURL( factoryURL, "_blank", 0, new PropertyValue[ 0 ] ) + ); + } + + + + /* ------------------------------------------------------------------ */ + public static DocumentHelper blankDocument( XComponentContext xCtx, DocumentType eType ) throws com.sun.star.uno.Exception + { + XComponent document = implCreateBlankDocument( xCtx, getDocumentFactoryURL( eType ) ); + if ( eType == DocumentType.CALC ) + return new SpreadsheetDocument( xCtx, document ); + + return new DocumentHelper( xCtx, document ); + } + + /* ------------------------------------------------------------------ */ + /** retrieves the current view of the document + @return + the view component, queried for the interface described by aInterfaceClass + */ + public DocumentViewHelper getCurrentView( ) + { + // get the model interface for the document + XModel xDocModel = UnoRuntime.queryInterface(XModel.class, m_documentComponent ); + // get the current controller for the document - as a controller is tied to a view, + // this gives us the currently active view for the document. + XController xController = xDocModel.getCurrentController(); + + if ( classify() == DocumentType.CALC ) + return new SpreadsheetView( m_orb, this, xController ); + + return new DocumentViewHelper( m_orb, this, xController ); + } + + /* ------------------------------------------------------------------ */ + /** creates a new form which is a child of the given form components container + + @param xParentContainer + The parent container for the new form + @param sInitialName + The initial name of the form. May be null, in this case the default (which + is an implementation detail) applies. + */ + private XIndexContainer createSubForm( XIndexContainer xParentContainer, String sInitialName ) + throws com.sun.star.uno.Exception + { + // create a new form + Object xNewForm = m_orb.createInstance( "com.sun.star.form.component.DataForm" ); + + // insert + xParentContainer.insertByIndex( xParentContainer.getCount(), xNewForm ); + + // set the name if necessary + if ( null != sInitialName ) + { + XPropertySet xFormProps = UNO.queryPropertySet( xNewForm ); + xFormProps.setPropertyValue( "Name", sInitialName ); + } + + // outta here + return UnoRuntime.queryInterface( XIndexContainer.class, xNewForm ); + } + + /* ------------------------------------------------------------------ */ + /** creates a new form which is a child of the given form components container + + @param aParentContainer + The parent container for the new form + @param sInitialName + The initial name of the form. May be null, in this case the default (which + is an implementation detail) applies. + */ + public XIndexContainer createSubForm( Object aParentContainer, String sInitialName ) + throws com.sun.star.uno.Exception + { + XIndexContainer xParentContainer = UnoRuntime.queryInterface( + XIndexContainer.class, aParentContainer ); + return createSubForm( xParentContainer, sInitialName ); + } + + /* ------------------------------------------------------------------ */ + /** creates a form which is a sibling of the given form + @param aForm + A sinbling of the to be created form. + + @param sInitialName + The initial name of the form. May be null, in this case the default (which + is an implementation detail) applies. + */ + public XIndexContainer createSiblingForm( Object aForm, String sInitialName ) throws com.sun.star.uno.Exception + { + // get the parent + XChild xAsChild = UnoRuntime.queryInterface( XChild.class, aForm ); + XIndexContainer xContainer = UnoRuntime.queryInterface( + XIndexContainer.class, xAsChild.getParent() ); + // append a new form to this parent container + return createSubForm( xContainer, sInitialName ); + } + + /* ------------------------------------------------------------------ */ + /** retrieves the document model which a given form component belongs to + */ + public static DocumentHelper getDocumentForComponent( Object aFormComponent, XComponentContext xCtx ) + { + XChild xChild = UnoRuntime.queryInterface( XChild.class, aFormComponent ); + XModel xModel = null; + while ( ( null != xChild ) && ( null == xModel ) ) + { + XInterface xParent = (XInterface)xChild.getParent(); + xModel = UnoRuntime.queryInterface( XModel.class, xParent ); + xChild = UnoRuntime.queryInterface( XChild.class, xParent ); + } + + return new DocumentHelper( xCtx, xModel ); + } + + /* ------------------------------------------------------------------ */ + /** returns a URL which can be used to create a document of a certain type + */ + private static String getDocumentFactoryURL( DocumentType eType ) + { + if ( eType == DocumentType.WRITER ) + return "private:factory/swriter"; + if ( eType == DocumentType.CALC ) + return "private:factory/scalc"; + if ( eType == DocumentType.DRAWING ) + return "private:factory/sdraw"; + return "private:factory/swriter"; + } + + /* ------------------------------------------------------------------ */ + /** classifies a document + */ + public DocumentType classify( ) + { + XServiceInfo xSI = UnoRuntime.queryInterface( + XServiceInfo.class, m_documentComponent ); + + if ( xSI.supportsService( "com.sun.star.text.TextDocument" ) ) + return DocumentType.WRITER; + else if ( xSI.supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) ) + return DocumentType.CALC; + else if ( xSI.supportsService( "com.sun.star.drawing.DrawingDocument" ) ) + return DocumentType.DRAWING; + + return DocumentType.UNKNOWN; + } + /* ------------------------------------------------------------------ */ + /** retrieves a com.sun.star.drawing.DrawPage of the document, denoted by index + * @param index + * the index of the draw page<br> + * @throws + * com.sun.star.lang.IndexOutOfBoundsException + * com.sun.star.lang.WrappedTargetException + */ + protected XDrawPage getDrawPage( int index ) throws com.sun.star.lang.IndexOutOfBoundsException, com.sun.star.lang.WrappedTargetException + { + XDrawPagesSupplier xSuppPages = UnoRuntime.queryInterface( + XDrawPagesSupplier.class, getDocument() ); + XDrawPages xPages = xSuppPages.getDrawPages(); + + return UnoRuntime.queryInterface( XDrawPage.class, xPages.getByIndex( index ) ); + } + + /* ------------------------------------------------------------------ */ + /** retrieves the <type scope="com.sun.star.drawing">DrawPage</type> of the document + */ + protected XDrawPage getMainDrawPage( ) throws com.sun.star.uno.Exception + { + XDrawPage xReturn; + + // in case of a Writer document, this is rather easy: simply ask the XDrawPageSupplier + XDrawPageSupplier xSuppPage = UnoRuntime.queryInterface( + XDrawPageSupplier.class, getDocument() ); + if ( null != xSuppPage ) + xReturn = xSuppPage.getDrawPage(); + else + { // the model itself is no draw page supplier - okay, it may be a Writer or Calc document + // (or any other multi-page document) + XDrawPagesSupplier xSuppPages = UnoRuntime.queryInterface( + XDrawPagesSupplier.class, getDocument() ); + XDrawPages xPages = xSuppPages.getDrawPages(); + + xReturn = UnoRuntime.queryInterface( XDrawPage.class, xPages.getByIndex( 0 ) ); + + // Note that this is no really error-proof code: If the document model does not support the + // XDrawPagesSupplier interface, or if the pages collection returned is empty, this will break. + } + + return xReturn; + } + + /* ------------------------------------------------------------------ */ + /** retrieves the root of the hierarchy of form components + */ + protected XNameContainer getFormComponentTreeRoot( ) throws com.sun.star.uno.Exception + { + XFormsSupplier xSuppForms = UnoRuntime.queryInterface( + XFormsSupplier.class, getMainDrawPage( ) ); + + XNameContainer xFormsCollection = null; + if ( null != xSuppForms ) + { + xFormsCollection = xSuppForms.getForms(); + } + return xFormsCollection; + } + + /* ------------------------------------------------------------------ */ + /** creates a component at the service factory provided by the document + */ + public XInterface createInstance( String serviceSpecifier ) throws com.sun.star.uno.Exception + { + XMultiServiceFactory xORB = UnoRuntime.queryInterface( XMultiServiceFactory.class, + m_documentComponent ); + return (XInterface)xORB.createInstance( serviceSpecifier ); + } + + /* ------------------------------------------------------------------ */ + /** creates a component at the service factory provided by the document + */ + public XInterface createInstanceWithArguments( String serviceSpecifier, Object[] arguments ) throws com.sun.star.uno.Exception + { + XMultiServiceFactory xORB = UnoRuntime.queryInterface( XMultiServiceFactory.class, + m_documentComponent ); + return (XInterface) xORB.createInstanceWithArguments( serviceSpecifier, arguments ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/DocumentType.java b/odk/examples/DevelopersGuide/Forms/DocumentType.java new file mode 100644 index 000000000..3a8e83beb --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/DocumentType.java @@ -0,0 +1,40 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +/** a helper "enumeration class" for classifying a document type +*/ +public class DocumentType extends com.sun.star.uno.Enum +{ + private DocumentType( int value ) + { + super( value ); + } + + + + public static final DocumentType WRITER = new DocumentType(0); + public static final DocumentType CALC = new DocumentType(1); + public static final DocumentType DRAWING = new DocumentType(2); + public static final DocumentType UNKNOWN = new DocumentType(-1); + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/DocumentViewHelper.java b/odk/examples/DevelopersGuide/Forms/DocumentViewHelper.java new file mode 100644 index 000000000..771b22784 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/DocumentViewHelper.java @@ -0,0 +1,215 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +import com.sun.star.awt.XControl; +import com.sun.star.awt.XControlModel; +import com.sun.star.awt.XWindow; +import com.sun.star.beans.PropertyValue; +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.XIndexContainer; +import com.sun.star.form.FormComponentType; +import com.sun.star.form.XForm; +import com.sun.star.form.runtime.XFormController; +import com.sun.star.frame.XController; +import com.sun.star.frame.XDispatch; +import com.sun.star.frame.XDispatchProvider; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.URL; +import com.sun.star.util.XURLTransformer; +import com.sun.star.view.XControlAccess; +import com.sun.star.view.XFormLayerAccess; + + +/**************************************************************************/ +/** provides a small wrapper around a document view +*/ +class DocumentViewHelper +{ + private XMultiServiceFactory m_orb; + private XController m_controller; + private DocumentHelper m_document; + + /* ------------------------------------------------------------------ */ + final protected XController getController() + { + return m_controller; + } + + /* ------------------------------------------------------------------ */ + final protected DocumentHelper getDocument() + { + return m_document; + } + + /* ------------------------------------------------------------------ */ + public DocumentViewHelper( XMultiServiceFactory orb, DocumentHelper document, XController controller ) + { + m_orb = orb; + m_document = document; + m_controller = controller; + } + + /* ------------------------------------------------------------------ */ + /** Quick access to a given interface of the view + @param aInterfaceClass + the class of the interface which shall be returned + */ + private <T> T get( Class<T> aInterfaceClass ) + { + return UnoRuntime.queryInterface( aInterfaceClass, m_controller ); + } + + /* ------------------------------------------------------------------ */ + /** retrieves a dispatcher for the given URL, obtained at the current view of the document + @param aURL + a one-element array. The first element must contain a valid + <member scope="com.sun.star.util">URL::Complete</member> value. Upon return, the URL is correctly + parsed. + @return + the dispatcher for the URL in question + */ + private XDispatch getDispatcher( URL[] aURL ) throws java.lang.Exception + { + XDispatch xReturn = null; + + // go get the current view + XController xController = get( XController.class ); + // go get the dispatch provider of its frame + XDispatchProvider xProvider = UnoRuntime.queryInterface( + XDispatchProvider.class, xController.getFrame() ); + if ( null != xProvider ) + { + // need a URLTransformer + XURLTransformer xTransformer = UnoRuntime.queryInterface( + XURLTransformer.class, m_orb.createInstance( "com.sun.star.util.URLTransformer" ) ); + xTransformer.parseStrict( aURL ); + + xReturn = xProvider.queryDispatch( aURL[0], "", 0 ); + } + return xReturn; + } + + + + /* ------------------------------------------------------------------ */ + /* retrieves the form controller belonging to a given logical form + */ + public XFormController getFormController( Object _form ) + { + XFormLayerAccess formLayer = get( XFormLayerAccess.class ); + return formLayer.getFormController( UnoRuntime.queryInterface( XForm.class, _form ) ); + } + + /* ------------------------------------------------------------------ */ + /** retrieves a control within the current view of a document + @param xModel + specifies the control model whose control should be located + @return + the control tied to the model + */ + private XControl getFormControl( XControlModel xModel ) throws com.sun.star.uno.Exception + { + // the current view of the document + XControlAccess xCtrlAcc = get( XControlAccess.class ); + // delegate the task of looking for the control + return xCtrlAcc.getControl( xModel ); + } + + /* ------------------------------------------------------------------ */ + public XControl getFormControl( Object aModel ) throws com.sun.star.uno.Exception + { + XControlModel xModel = UnoRuntime.queryInterface( XControlModel.class, aModel ); + return getFormControl( xModel ); + } + + /* ------------------------------------------------------------------ */ + public <T> T getFormControl( Object aModel, Class<T> aInterfaceClass ) throws com.sun.star.uno.Exception + { + XControlModel xModel = UnoRuntime.queryInterface( XControlModel.class, aModel ); + return UnoRuntime.queryInterface( aInterfaceClass, getFormControl( xModel ) ); + } + + /* ------------------------------------------------------------------ */ + /** toggles the design mode of the form layer of active view of our sample document + */ + protected void toggleFormDesignMode( ) throws java.lang.Exception + { + // get a dispatcher for the toggle URL + URL[] aToggleURL = new URL[] { new URL() }; + aToggleURL[0].Complete = ".uno:SwitchControlDesignMode"; + XDispatch xDispatcher = getDispatcher( aToggleURL ); + + // dispatch the URL - this will result in toggling the mode + PropertyValue[] aDummyArgs = new PropertyValue[] { }; + xDispatcher.dispatch( aToggleURL[0], aDummyArgs ); + } + + /* ------------------------------------------------------------------ */ + /** sets the focus to a specific control + @param xModel + a control model. The focus is set to that control which is part of our view + and associated with the given model. + */ + public void grabControlFocus( Object xModel ) throws com.sun.star.uno.Exception + { + // look for the control from the current view which belongs to the model + XControl xControl = getFormControl( xModel ); + + // the focus can be set to an XWindow only + XWindow xControlWindow = UnoRuntime.queryInterface( XWindow.class, + xControl ); + + // grab the focus + xControlWindow.setFocus(); + } + + /* ------------------------------------------------------------------ */ + /** sets the focus to the first control + */ + protected void grabControlFocus( ) throws java.lang.Exception + { + // the forms container of our document + XIndexContainer xForms = UNO.queryIndexContainer( m_document.getFormComponentTreeRoot( ) ); + // the first form + XIndexContainer xForm = UNO.queryIndexContainer( xForms.getByIndex( 0 ) ); + + // the first control model which is no FixedText (FixedText's can't have the focus) + for ( int i = 0; i<xForm.getCount(); ++i ) + { + XPropertySet xControlProps = UNO.queryPropertySet( xForm.getByIndex( i ) ); + if ( FormComponentType.FIXEDTEXT != ((Short)xControlProps.getPropertyValue( "ClassId" )).shortValue() ) + { + XControlModel xControlModel = UnoRuntime.queryInterface( + XControlModel.class, xControlProps ); + // set the focus to this control + grabControlFocus( xControlModel ); + // outta here + break; + } + } + + // Note that we simply took the first control model from the hierarchy. This does state nothing + // about the location of the respective control in the view. A control model is tied to a control + // shape, and the shapes are where the geometry information such as position and size is hung up. + // So you could easily have a document where the first control model is bound to a shape which + // has a greater ordinate than any other control model. + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/FLTools.java b/odk/examples/DevelopersGuide/Forms/FLTools.java new file mode 100644 index 000000000..ea1467b52 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/FLTools.java @@ -0,0 +1,216 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import com.sun.star.uno.*; +import com.sun.star.lang.*; +import com.sun.star.beans.*; +import com.sun.star.container.*; +import com.sun.star.awt.*; +import com.sun.star.form.*; + + +/** provides global helpers +*/ +public class FLTools +{ + + + + + /* ------------------------------------------------------------------ */ + /** returns the name of the given form component + */ + private static String getName( Object aFormComponent ) + { + XNamed xNamed = UnoRuntime.queryInterface( XNamed.class, + aFormComponent ); + String sName = ""; + if ( null != xNamed ) + sName = xNamed.getName(); + return sName; + } + + /* ------------------------------------------------------------------ */ + /** returns the label of the given form component + */ + public static String getLabel( Object aFormComponent ) throws com.sun.star.uno.Exception + { + String sLabel = ""; + + XPropertySet xProps = UNO.queryPropertySet( aFormComponent ); + XPropertySetInfo xPSI = ( null != xProps ) ? xProps.getPropertySetInfo() : null; + if ( null == xPSI ) + { // no property set or no property set info + // can't do anything except falling back to the name + return getName( aFormComponent ); + } + + // first check if the component has a LabelControl + if ( xPSI.hasPropertyByName( "LabelControl" ) ) + sLabel = getLabel( xProps.getPropertyValue( "LabelControl" ) ); + + // no LabelControl or no label at the LabelControl + if ( 0 == sLabel.length() ) + { + // a "Label" property? + if ( xPSI.hasPropertyByName( "Label" ) ) + sLabel = (String)xProps.getPropertyValue( "Label" ); + + if ( 0 == sLabel.length() ) + { // no Label property or no label set + // -> fallback to the component name + sLabel = getName( aFormComponent ); + } + } + + return sLabel; + } + + + + /* ------------------------------------------------------------------ */ + /** retrieves the parent of the given object + */ + private static <T> T getParent( Object aComponent, Class<T> aInterfaceClass ) + { + XChild xAsChild = UnoRuntime.queryInterface( XChild.class, aComponent ); + + return UnoRuntime.queryInterface( aInterfaceClass, xAsChild.getParent() ); + } + + /* ------------------------------------------------------------------ */ + /** retrieves the parent of the given object + */ + static XPropertySet getParent( Object aComponent ) + { + return getParent( aComponent, XPropertySet.class ); + } + + /* ------------------------------------------------------------------ */ + /** disposes the component given + */ + public static void disposeComponent( Object xComp ) throws java.lang.RuntimeException + { + XComponent xComponent = UnoRuntime.queryInterface( XComponent.class, + xComp ); + if ( null != xComponent ) + xComponent.dispose(); + } + + /* ------------------------------------------------------------------ */ + /** gets the XControlModel for a control + */ + public static <T> T getModel( Object aControl, Class<T> aInterfaceClass ) + { + XControl xControl = UnoRuntime.queryInterface( + XControl.class, aControl ); + XControlModel xModel = null; + if ( null != xControl ) + xModel = xControl.getModel(); + + return UnoRuntime.queryInterface( aInterfaceClass, xModel ); + } + + /* ------------------------------------------------------------------ */ + /** retrieves the type of a form component. + <p>Speaking strictly, the function recognizes more than form components. Especially, + it survives a null argument. which means it can be safely applied to the a top-level + forms container; and it is able to classify grid columns (which are no form components) + as well.</p> + */ + public static String classifyFormComponentType( XPropertySet xComponent ) throws com.sun.star.uno.Exception + { + String sType = "<unknown component>"; + + XServiceInfo xSI = UNO.queryServiceInfo( xComponent ); + + XPropertySetInfo xPSI = null; + if ( null != xComponent ) + xPSI = xComponent.getPropertySetInfo(); + + if ( ( null != xPSI ) && xPSI.hasPropertyByName( "ClassId" ) ) + { + // get the ClassId property + XPropertySet xCompProps = UNO.queryPropertySet( xComponent ); + + Short nClassId = (Short)xCompProps.getPropertyValue( "ClassId" ); + switch ( nClassId.intValue() ) + { + case FormComponentType.COMMANDBUTTON: sType = "Command button"; break; + case FormComponentType.RADIOBUTTON : sType = "Radio button"; break; + case FormComponentType.IMAGEBUTTON : sType = "Image button"; break; + case FormComponentType.CHECKBOX : sType = "Check Box"; break; + case FormComponentType.LISTBOX : sType = "List Box"; break; + case FormComponentType.COMBOBOX : sType = "Combo Box"; break; + case FormComponentType.GROUPBOX : sType = "Group Box"; break; + case FormComponentType.FIXEDTEXT : sType = "Fixed Text"; break; + case FormComponentType.GRIDCONTROL : sType = "Grid Control"; break; + case FormComponentType.FILECONTROL : sType = "File Control"; break; + case FormComponentType.HIDDENCONTROL: sType = "Hidden Control"; break; + case FormComponentType.IMAGECONTROL : sType = "Image Control"; break; + case FormComponentType.DATEFIELD : sType = "Date Field"; break; + case FormComponentType.TIMEFIELD : sType = "Time Field"; break; + case FormComponentType.NUMERICFIELD : sType = "Numeric Field"; break; + case FormComponentType.CURRENCYFIELD: sType = "Currency Field"; break; + case FormComponentType.PATTERNFIELD : sType = "Pattern Field"; break; + + case FormComponentType.TEXTFIELD : + // there are two known services with this class id: the usual text field, + // and the formatted field + sType = "Text Field"; + if ( ( null != xSI ) && xSI.supportsService( "com.sun.star.form.component.FormattedField" ) ) + { + sType = "Formatted Field"; + } + break; + + default: + break; + } + } + else + { + if ( ( null != xSI ) && xSI.supportsService( "com.sun.star.form.component.DataForm" ) ) + { + sType = "Form"; + } + } + + return sType; + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/FormLayer.java b/odk/examples/DevelopersGuide/Forms/FormLayer.java new file mode 100644 index 000000000..11a9ce952 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/FormLayer.java @@ -0,0 +1,272 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +import com.sun.star.uno.UnoRuntime; + +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.XPropertySetInfo; +import com.sun.star.container.XIndexContainer; +import com.sun.star.container.XIndexAccess; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.drawing.XControlShape; +import com.sun.star.drawing.XShapes; +import com.sun.star.awt.Size; +import com.sun.star.awt.Point; +import com.sun.star.awt.XControlModel; +import com.sun.star.text.TextContentAnchorType; +import com.sun.star.drawing.XDrawPage; + +public class FormLayer +{ + private DocumentHelper m_document; + private int m_insertPage; + + /* ------------------------------------------------------------------ */ + /** Creates a new instance of FormLayer */ + public FormLayer( DocumentHelper _document ) + { + m_document = _document; + m_insertPage = -1; + } + + + + + + /* ------------------------------------------------------------------ */ + /** creates a control in the document + + <p>Note that <em>control<em> here is an incorrect terminology. What the method really does is + it creates a control shape, together with a control model, and inserts them into the document model. + This will result in every view to this document creating a control described by the model-shape pair. + </p> + + @param sFormComponentService + the service name of the form component to create, e.g. "TextField" + @param nXPos + the abscissa of the position of the newly inserted shape + @param nXPos + the ordinate of the position of the newly inserted shape + @param nWidth + the width of the newly inserted shape + @param nHeight + the height of the newly inserted shape + @param xParentForm + the form to use as parent for the newly create form component. May be null, in this case + a default parent is chosen by the implementation + @return + the property access to the control's model + */ + protected XPropertySet createControlAndShape( String sFormComponentService, int nXPos, + int nYPos, int nWidth, int nHeight, XIndexContainer xParentForm ) throws java.lang.Exception + { + // let the document create a shape + XMultiServiceFactory xDocAsFactory = UnoRuntime.queryInterface( + XMultiServiceFactory.class, m_document.getDocument() ); + XControlShape xShape = UnoRuntime.queryInterface( XControlShape.class, + xDocAsFactory.createInstance( "com.sun.star.drawing.ControlShape" ) ); + + // position and size of the shape + xShape.setSize( new Size( nWidth * 100, nHeight * 100 ) ); + xShape.setPosition( new Point( nXPos * 100, nYPos * 100 ) ); + + // adjust the anchor so that the control is tied to the page + XPropertySet xShapeProps = UNO.queryPropertySet( xShape ); + TextContentAnchorType eAnchorType = TextContentAnchorType.AT_PARAGRAPH; + xShapeProps.setPropertyValue( "AnchorType", eAnchorType ); + + // create the form component (the model of a form control) + String sQualifiedComponentName = "com.sun.star.form.component." + sFormComponentService; + XControlModel xModel = UnoRuntime.queryInterface( XControlModel.class, + m_document.getOrb().createInstance( sQualifiedComponentName ) ); + + // insert the model into the form component hierarchy, if the caller gave us a location + if ( null != xParentForm ) + { + xParentForm.insertByIndex( xParentForm.getCount(), xModel ); + } + + // knitt them + xShape.setControl( xModel ); + + // add the shape to the shapes collection of the document + XDrawPage pageWhereToInsert = ( m_insertPage != -1 ) ? m_document.getDrawPage( m_insertPage ) : m_document.getMainDrawPage(); + + XShapes xDocShapes = UnoRuntime.queryInterface( XShapes.class, pageWhereToInsert ); + xDocShapes.add( xShape ); + + // some initializations which are the same for all controls + XPropertySet xModelProps = UNO.queryPropertySet( xModel ); + try + { + XPropertySetInfo xPSI = xModelProps.getPropertySetInfo(); + if ( xPSI.hasPropertyByName( "Border" ) ) + { + if ( ((Short)xModelProps.getPropertyValue( "Border" )).shortValue() == com.sun.star.awt.VisualEffect.LOOK3D ) + xModelProps.setPropertyValue( "Border", Short.valueOf( com.sun.star.awt.VisualEffect.FLAT ) ); + } + if ( xPSI.hasPropertyByName( "VisualEffect" ) ) + xModelProps.setPropertyValue( "VisualEffect", Short.valueOf( com.sun.star.awt.VisualEffect.FLAT ) ); + if ( m_document.classify() != DocumentType.CALC ) + if ( xPSI.hasPropertyByName( "BorderColor" ) ) + xModelProps.setPropertyValue( "BorderColor", Integer.valueOf( 0x00C0C0C0 ) ); + } + catch( com.sun.star.uno.Exception e ) + { + System.err.println(e); + e.printStackTrace( System.err ); + } + return xModelProps; + } + + /* ------------------------------------------------------------------ */ + /** creates a control in the document + + <p>Note that <em>control<em> here is an incorrect terminology. What the method really does is + it creates a control shape, together with a control model, and inserts them into the document model. + This will result in every view to this document creating a control described by the model-shape pair. + </p> + + @param sFormComponentService + the service name of the form component to create, e.g. "TextField" + @param nXPos + the abscissa of the position of the newly inserted shape + @param nXPos + the ordinate of the position of the newly inserted shape + @param nWidth + the width of the newly inserted shape + @param nHeight + the height of the newly inserted shape + @return + the property access to the control's model + */ + protected XPropertySet createControlAndShape( String sFormComponentService, int nXPos, + int nYPos, int nWidth, int nHeight ) throws java.lang.Exception + { + return createControlAndShape( sFormComponentService, nXPos, nYPos, nWidth, nHeight, null ); + } + + /* ------------------------------------------------------------------ */ + /** creates a line of controls, consisting of a label and a field for data input. + + <p>In opposite to the second form of this method, here the height of the field, + as well as the abscissa of the label, are under the control of the caller.</p> + + @param sControlType + specifies the type of the data input control + @param sFieldName + specifies the field name the text field should be bound to + @param sControlNamePostfix + specifies a postfix to append to the logical control names + @param nYPos + specifies the Y position of the line to start at + @param nHeight + the height of the field + @return + the control model of the created data input field + */ + protected XPropertySet insertControlLine( String sControlType, String sFieldName, String sControlNamePostfix, int nXPos, int nYPos, int nHeight ) + throws java.lang.Exception + { + // insert the label control + XPropertySet xLabelModel = createControlAndShape( "FixedText", nXPos, nYPos, 25, 6 ); + xLabelModel.setPropertyValue( "Label", sFieldName ); + + // insert the text field control + XPropertySet xFieldModel = createControlAndShape( sControlType, nXPos + 26, nYPos, 40, nHeight ); + xFieldModel.setPropertyValue( "DataField", sFieldName ); + // knit it to its label component + xFieldModel.setPropertyValue( "LabelControl", xLabelModel ); + + // some names, so later on we can find them + xLabelModel.setPropertyValue( "Name", sFieldName + sControlNamePostfix + "_Label" ); + xFieldModel.setPropertyValue( "Name", sFieldName + sControlNamePostfix ); + + return xFieldModel; + } + + /* ------------------------------------------------------------------ */ + /** creates a line of controls, consisting of a label and a field for data input. + + @param sControlType + specifies the type of the data input control + @param sFieldName + specifies the field name the text field should be bound to + @param nYPos + specifies the Y position of the line to start at + @return + the control model of the created data input field + */ + protected XPropertySet insertControlLine( String sControlType, String sFieldName, String sControlNamePostfix, int nYPos ) + throws java.lang.Exception + { + return insertControlLine( sControlType, sFieldName, sControlNamePostfix, 2, nYPos, 6 ); + } + + /* ------------------------------------------------------------------ */ + /** retrieves the radio button model with the given name and the given ref value + * @param form + * the parent form of the radio button model to find + * @param name + * the name of the radio button + * @param refValue + * the reference value of the radio button + */ + public XPropertySet getRadioModelByRefValue( XPropertySet form, String name, String refValue ) throws com.sun.star.uno.Exception, java.lang.Exception + { + XIndexAccess indexAccess = UnoRuntime.queryInterface( XIndexAccess.class, + form ); + + for ( int i=0; i<indexAccess.getCount(); ++i ) + { + XPropertySet control = UNO.queryPropertySet( indexAccess.getByIndex( i ) ); + + if ( ((String)control.getPropertyValue( "Name" )).equals( name ) ) + if ( ((String)control.getPropertyValue( "RefValue" )).equals( refValue ) ) + return control; + } + return null; + } + + /* ------------------------------------------------------------------ */ + /** retrieves the radio button model with the given name and the given tag + * @param form + * the parent form of the radio button model to find + * @param name + * the name of the radio button + * @param tag + * the tag of the radio button + */ + public XPropertySet getRadioModelByTag( XPropertySet form, String name, String tag ) throws com.sun.star.uno.Exception, java.lang.Exception + { + XIndexAccess indexAccess = UnoRuntime.queryInterface( XIndexAccess.class, + form ); + + for ( int i=0; i<indexAccess.getCount(); ++i ) + { + XPropertySet control = UNO.queryPropertySet( indexAccess.getByIndex( i ) ); + + if ( ((String)control.getPropertyValue( "Name" )).equals( name ) ) + if ( ((String)control.getPropertyValue( "Tag" )).equals( tag ) ) + return control; + } + return null; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/GridFieldValidator.java b/odk/examples/DevelopersGuide/Forms/GridFieldValidator.java new file mode 100644 index 000000000..8bf0aef63 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/GridFieldValidator.java @@ -0,0 +1,174 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +/**************************************************************************/ +import com.sun.star.uno.*; +import com.sun.star.beans.*; +import com.sun.star.form.*; +import com.sun.star.lang.*; +import com.sun.star.sdb.*; +import com.sun.star.task.*; + +/**************************************************************************/ +/** helper class for validating a grid field before it is updated + + <p>Actually, the mechanism for validating the field is not restricted to + grid control fields. Instead, it can be used for any bound controls.</p> +*/ +class GridFieldValidator implements XUpdateListener +{ + private XComponentContext m_xCtx; + private XPropertySet m_xWatchedColumn; + + private boolean m_bWatching; + + /* ------------------------------------------------------------------ */ + public GridFieldValidator( XComponentContext xCtx, XPropertySet xWatchedGridColumn ) + { + // remember + m_xCtx = xCtx; + m_xWatchedColumn = xWatchedGridColumn; + DocumentHelper.getDocumentForComponent(xWatchedGridColumn, + xCtx); + + m_bWatching = false; + } + + /* ------------------------------------------------------------------ */ + public void enableColumnWatch( boolean bEnable ) + { + if ( bEnable == m_bWatching ) + return; + + XUpdateBroadcaster xUpdate = UnoRuntime.queryInterface( + XUpdateBroadcaster.class, m_xWatchedColumn ); + + if ( bEnable ) + xUpdate.addUpdateListener( this ); + else + xUpdate.removeUpdateListener( this ); + + m_bWatching = bEnable; + } + + /* ------------------------------------------------------------------ */ + /** shows a message that we can't do several things due to an implementation error + */ + private void showInvalidValueMessage( ) + { + try + { + // build the message we want to show + String sMessage = "The column \""; + sMessage += FLTools.getLabel( m_xWatchedColumn ); + sMessage += "\" is not allowed to contain empty strings."; + + SQLContext aError = new SQLContext( + "Invalid Value Entered", + null, + "S1000", + 0, + new Any( new Type(), null ), + sMessage + ); + + // instantiate an interaction handler who can handle SQLExceptions + XInteractionHandler xHandler = UnoRuntime.queryInterface( + XInteractionHandler.class, + m_xCtx.getServiceManager().createInstanceWithContext( + "com.sun.star.task.InteractionHandler", m_xCtx ) ); + + // create a new request and execute it + InteractionRequest aRequest = new InteractionRequest( aError ); + xHandler.handle( aRequest ); + } + catch( com.sun.star.uno.Exception e ) + { + System.out.println(e); + e.printStackTrace(); + } + } + + /* ------------------------------------------------------------------ */ + // XUpdateListener overridables + /* ------------------------------------------------------------------ */ + public boolean approveUpdate( EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + boolean bApproved = true; + try + { + // the control model which fired the event + XPropertySet xSourceProps = UNO.queryPropertySet( aEvent.Source ); + + String sNewText = (String)xSourceProps.getPropertyValue( "Text" ); + if ( 0 == sNewText.length() ) + { + // say that the value is invalid + showInvalidValueMessage( ); + bApproved = false; + + // reset the control value + // for this, we take the current value from the row set field the control + // is bound to, and forward it to the control model + XColumn xBoundColumn = UNO.queryColumn( xSourceProps.getPropertyValue( "BoundField" ) ); + if ( null != xBoundColumn ) + { + xSourceProps.setPropertyValue( "Text", xBoundColumn.getString() ); + } + } + } + catch( com.sun.star.uno.Exception e ) + { + System.out.println(e); + e.printStackTrace(); + } + return bApproved; + } + + /* ------------------------------------------------------------------ */ + public void updated( EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + } + + /* ------------------------------------------------------------------ */ + // XEventListener overridables + /* ------------------------------------------------------------------ */ + public void disposing( EventObject aEvent ) + { + // not interested in + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/HsqlDatabase.java b/odk/examples/DevelopersGuide/Forms/HsqlDatabase.java new file mode 100644 index 000000000..fd2cd6ccf --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/HsqlDatabase.java @@ -0,0 +1,184 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +import com.sun.star.beans.PropertyValue; +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.XNameAccess; +import com.sun.star.frame.XStorable; +import com.sun.star.sdb.XOfficeDatabaseDocument; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XCloseable; +import com.sun.star.sdbc.XConnection; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.sdb.XDocumentDataSource; +import com.sun.star.sdbc.XDataSource; +import com.sun.star.uno.XComponentContext; +import java.io.File; + +import com.sun.star.util.CloseVetoException; + +public class HsqlDatabase +{ + private XComponentContext m_context; + // the URL of the temporary file used for the database document + private String m_databaseDocumentFile; + // the database document + private XOfficeDatabaseDocument m_databaseDocument; + // the data source belonging to the database document + // the default connection + private XConnection m_connection; + + + public HsqlDatabase( XComponentContext _context ) throws Exception + { + m_context = _context; + createDBDocument(); + } + + + public HsqlDatabase( XComponentContext _context, String _existingDocumentURL ) throws Exception + { + m_context = _context; + createDBDocument( _existingDocumentURL ); + } + + + private void createDBDocument( String _docURL ) throws Exception + { + m_databaseDocumentFile = _docURL; + + XNameAccess dbContext = UnoRuntime.queryInterface( XNameAccess.class, + m_context.getServiceManager().createInstanceWithContext( "com.sun.star.sdb.DatabaseContext", m_context ) ); + XDocumentDataSource dataSource = UnoRuntime.queryInterface( XDocumentDataSource.class, + dbContext.getByName( _docURL ) ); + + m_databaseDocument = dataSource.getDatabaseDocument(); + } + + /** creates an empty database document in a temporary location + */ + private void createDBDocument() throws Exception + { + File documentFile = File.createTempFile("testdb",".odb"); + documentFile.deleteOnExit(); + m_databaseDocumentFile = URLHelper.getFileURLFromSystemPath( documentFile ); + + m_databaseDocument = UnoRuntime.queryInterface( + XOfficeDatabaseDocument.class, m_context.getServiceManager().createInstanceWithContext( + "com.sun.star.sdb.OfficeDatabaseDocument", m_context ) ); + + XPropertySet dsProperties = UnoRuntime.queryInterface( XPropertySet.class, m_databaseDocument.getDataSource() ); + dsProperties.setPropertyValue("URL", "sdbc:embedded:hsqldb"); + + XStorable storable = UnoRuntime.queryInterface( XStorable.class, m_databaseDocument ); + storable.storeAsURL( m_databaseDocumentFile, new PropertyValue[]{} ); + } + + /** closes the database document + * + * Any CloseVetoExceptions fired by third parties are ignored, and any reference to the + * database document is released. + */ + private void close() + { + // close connection + XCloseable closeConn = UnoRuntime.queryInterface( XCloseable.class, + m_connection ); + if ( closeConn != null ) + { + try + { + closeConn.close(); + } + catch( SQLException e ) + { + } + } + m_connection = null; + + // close document + com.sun.star.util.XCloseable closeDoc = UnoRuntime.queryInterface( + com.sun.star.util.XCloseable.class, m_databaseDocument ); + if ( closeDoc != null ) + { + try + { + closeDoc.close( true ); + } + catch( CloseVetoException e ) + { + } + } + m_databaseDocument = null; + } + + /** closes the document, and deletes the underlying file + */ + private void closeAndDelete() + { + close(); + + if ( m_databaseDocumentFile != null ) + { + try + { + File file = new File(m_databaseDocumentFile); + file.delete(); + } + catch(Exception e) + { + } + m_databaseDocumentFile = null; + } + } + + /** returns the underlying database document + */ + public XOfficeDatabaseDocument getDatabaseDocument() + { + return m_databaseDocument; + } + + /** returns the associated data source + */ + public XDataSource getDataSource() + { + return m_databaseDocument.getDataSource(); + } + + + + /** returns the URL of the ODB document represented by this instance + */ + public String getDocumentURL() + { + return m_databaseDocumentFile; + } + + + + @Override + protected void finalize() throws Throwable + { + closeAndDelete(); + super.finalize(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/InteractionRequest.java b/odk/examples/DevelopersGuide/Forms/InteractionRequest.java new file mode 100644 index 000000000..52ec3b8ef --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/InteractionRequest.java @@ -0,0 +1,71 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import java.util.ArrayList; + +import com.sun.star.task.XInteractionContinuation; +import com.sun.star.task.XInteractionRequest; + +/**************************************************************************/ +/** helper class for implementing an interaction request. +*/ +class InteractionRequest implements XInteractionRequest +{ + private Object m_aRequest; + private ArrayList<XInteractionContinuation> m_aContinuations; + + /* ------------------------------------------------------------------ */ + public InteractionRequest( Object aRequest ) + { + m_aRequest = aRequest; + m_aContinuations = new ArrayList<XInteractionContinuation>(); + } + + + + /* ------------------------------------------------------------------ */ + public Object getRequest( ) + { + return m_aRequest; + } + + /* ------------------------------------------------------------------ */ + public XInteractionContinuation[] getContinuations( ) + { + return m_aContinuations.toArray( new XInteractionContinuation[ m_aContinuations.size() ] ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/KeyGenerator.java b/odk/examples/DevelopersGuide/Forms/KeyGenerator.java new file mode 100644 index 000000000..43e5acdfa --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/KeyGenerator.java @@ -0,0 +1,434 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import com.sun.star.uno.*; +import com.sun.star.beans.*; +import com.sun.star.form.*; +import com.sun.star.lang.*; +import com.sun.star.sdb.*; +import com.sun.star.sdbc.*; +import com.sun.star.sdbcx.*; +import com.sun.star.container.*; +import com.sun.star.awt.*; + +/**************************************************************************/ +/** base class for helpers dealing with unique column values +*/ +class UniqueColumnValue +{ + /* ------------------------------------------------------------------ */ + /** extracts the name of the table a form is based on. + + <p>This method works for forms based directly on tables, and for forms based on statements, which + themself are based on one table.<br> + Everything else (especially forms based on queries) is not yet implemented.</p> + */ + private String extractTableName( XPropertySet xForm ) throws com.sun.star.uno.Exception + { + String sReturn; + + Integer aCommandType = (Integer)xForm.getPropertyValue( "CommandType" ); + String sCommand = (String)xForm.getPropertyValue( "Command" ); + + if ( CommandType.COMMAND == aCommandType.intValue() ) + { + // get the connection from the form + XConnection xFormConn = UnoRuntime.queryInterface( XConnection.class, + xForm.getPropertyValue( "ActiveConnection" ) ); + // and let it create a composer for us + XSQLQueryComposerFactory xComposerFac = + UnoRuntime.queryInterface( + XSQLQueryComposerFactory.class, xFormConn ); + XSQLQueryComposer xComposer = xComposerFac.createQueryComposer( ); + + // let this composer analyze the command + xComposer.setQuery( sCommand ); + + // and ask it for the table(s) + XTablesSupplier xSuppTables = UnoRuntime.queryInterface( + XTablesSupplier.class, xComposer ); + XNameAccess xTables = xSuppTables.getTables(); + + // simply take the first table name + String[] aNames = xTables.getElementNames( ); + sCommand = aNames[0]; + } + + return sCommand; + } + + /* ------------------------------------------------------------------ */ + /** generates a statement which can be used to create a unique (in all conscience) value + for the column given. + <p>Currently, the implementation uses a very simple approach - it just determines the maximum of currently + existing values in the column. If your concrete data source supports a more sophisticated approach of generating + unique values, you probably want to adjust the <code>SELECT</code> statement below accordingly.</p> + + @returns + a String which can be used as statement to retrieve a unique value for the given column. + The result set resulting from such an execution contains the value in its first column. + */ + private String composeUniqueyKeyStatement( XPropertySet xForm, String sFieldName ) throws com.sun.star.uno.Exception + { + String sStatement = "SELECT MAX( "; + sStatement += sFieldName; + sStatement += ") + 1 FROM "; + // the table name is a property of the form + sStatement += extractTableName( xForm ); + + // note that the implementation is imperfect (besides the problem that MAX is not a really good solution + // for a database with more that one client): + // It does not quote the field and the table name. This needs to be done if the database is intolerant + // against such things - the XDatabaseMetaData, obtained from the connection, would be needed then + // Unfortunately, there is no UNO service doing this - it would need to be implemented manually. + + return sStatement; + } + + /* ------------------------------------------------------------------ */ + /** generates a unique (in all conscience) key into the column given + @param xForm + the form which contains the column in question + @param sFieldName + the name of the column + */ + private int generatePrimaryKey( XPropertySet xForm, String sFieldName ) throws com.sun.star.uno.Exception + { + // get the current connection of the form + XConnection xConn = UnoRuntime.queryInterface( + XConnection.class, xForm.getPropertyValue( "ActiveConnection" ) ); + // let it create a new statement + XStatement xStatement = xConn.createStatement(); + + // build the query string to determine a free value + String sStatement = composeUniqueyKeyStatement( xForm, sFieldName ); + + // execute the query + XResultSet xResults = xStatement.executeQuery( sStatement ); + + // move the result set to the first record + xResults.next( ); + + // get the value + XRow xRow = UnoRuntime.queryInterface( XRow.class, xResults ); + int nFreeValue = xRow.getInt( 1 ); + + // dispose the temporary objects + FLTools.disposeComponent( xStatement ); + // this should get rid of the result set, too + + return nFreeValue; + } + + /* ------------------------------------------------------------------ */ + /** inserts a unique (in all conscience) key into the column given + @param xForm + the form which contains the column in question + @param sFieldName + the name of the column + */ + public void insertPrimaryKey( XPropertySet xForm, String sFieldName ) throws com.sun.star.uno.Exception + { + // check the privileges + Integer aConcurrency = (Integer)xForm.getPropertyValue( "ResultSetConcurrency" ); + if ( ResultSetConcurrency.READ_ONLY != aConcurrency.intValue() ) + { + // get the column object + XColumnsSupplier xSuppCols = UnoRuntime.queryInterface( + XColumnsSupplier.class, xForm ); + XNameAccess xCols = xSuppCols.getColumns(); + XColumnUpdate xCol = UnoRuntime.queryInterface( + XColumnUpdate.class, xCols.getByName( sFieldName ) ); + + xCol.updateInt( generatePrimaryKey( xForm, sFieldName ) ); + } + } +} + +/**************************************************************************/ +/** base class for helpers dealing with unique column values +*/ +class KeyGeneratorForReset extends UniqueColumnValue implements XResetListener +{ + /* ------------------------------------------------------------------ */ + private DocumentViewHelper m_aView; + private String m_sFieldName; + + /* ------------------------------------------------------------------ */ + /** ctor + @param aView + the view which shall be used to focus controls + @param sFieldName + the name of the field for which keys should be generated + */ + public KeyGeneratorForReset( String sFieldName, DocumentViewHelper aView ) + { + m_sFieldName = sFieldName; + m_aView = aView; + } + + /* ------------------------------------------------------------------ */ + /** sets the focus to the first control which is no fixed text, and not the + one we're defaulting + */ + private void defaultNewRecordFocus( XPropertySet xForm ) throws com.sun.star.uno.Exception + { + XIndexAccess xFormAsContainer = UnoRuntime.queryInterface( + XIndexAccess.class, xForm ); + for ( int i = 0; i<xFormAsContainer.getCount(); ++i ) + { + // the model + XPropertySet xModel = UNO.queryPropertySet( xFormAsContainer.getByIndex( i ) ); + + // check if it's a valid leaf (no sub form or such) + XPropertySetInfo xPSI = xModel.getPropertySetInfo( ); + if ( ( null == xPSI ) || !xPSI.hasPropertyByName( "ClassId" ) ) + continue; + + // check if it's a fixed text + Short nClassId = (Short)xModel.getPropertyValue( "ClassId" ); + if ( FormComponentType.FIXEDTEXT == nClassId.shortValue() ) + continue; + + // check if it is bound to the field we are responsible for + if ( !xPSI.hasPropertyByName( "DataField" ) ) + continue; + + String sFieldDataSource = (String)xModel.getPropertyValue( "DataField" ); + if ( sFieldDataSource.equals( m_sFieldName ) ) + continue; + + // both conditions do not apply + // -> set the focus into the respective control + XControlModel xCM = UNO.queryControlModel( xModel ); + m_aView.grabControlFocus( xCM); + break; + } + } + + /* ------------------------------------------------------------------ */ + // XResetListener overridables + /* ------------------------------------------------------------------ */ + public boolean approveReset( com.sun.star.lang.EventObject rEvent ) throws com.sun.star.uno.RuntimeException + { + // not interested in vetoing this + return true; + } + + /* ------------------------------------------------------------------ */ + public void resetted( com.sun.star.lang.EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + // check if this reset occurred because we're on a new record + XPropertySet xFormProps = UNO.queryPropertySet( aEvent.Source ); + try + { + Boolean aIsNew = (Boolean)xFormProps.getPropertyValue( "IsNew" ); + if ( aIsNew.booleanValue() ) + { // yepp + + // we're going to modify the record, though after that, to the user, it should look + // like it has not been modified + // So we need to ensure that we do not change the IsModified property with whatever we do + Object aModifiedFlag = xFormProps.getPropertyValue( "IsModified" ); + + // now set the value + insertPrimaryKey( xFormProps, m_sFieldName ); + + // then restore the flag + xFormProps.setPropertyValue( "IsModified", aModifiedFlag ); + + // still one thing ... would be nice to have the focus in a control which is + // the one which's value we just defaulted + defaultNewRecordFocus( xFormProps ); + } + } + catch( com.sun.star.uno.Exception e ) + { + System.out.println(e); + e.printStackTrace(); + } + } + /* ------------------------------------------------------------------ */ + // XEventListener overridables + /* ------------------------------------------------------------------ */ + public void disposing( EventObject aEvent ) + { + // not interested in + } +} + + +/**************************************************************************/ +/** base class for helpers dealing with unique column values +*/ +class KeyGeneratorForUpdate extends UniqueColumnValue implements XRowSetApproveListener +{ + /* ------------------------------------------------------------------ */ + private String m_sFieldName; + + /* ------------------------------------------------------------------ */ + public KeyGeneratorForUpdate( String sFieldName ) + { + m_sFieldName = sFieldName; + } + + /* ------------------------------------------------------------------ */ + // XRowSetApproveListener overridables + /* ------------------------------------------------------------------ */ + public boolean approveCursorMove( com.sun.star.lang.EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + // not interested in vetoing moves + return true; + } + + /* ------------------------------------------------------------------ */ + public boolean approveRowChange( RowChangeEvent aEvent ) throws com.sun.star.uno.RuntimeException + { + if ( RowChangeAction.INSERT == aEvent.Action ) + { + try + { + // the affected form + XPropertySet xFormProps = UNO.queryPropertySet( aEvent.Source ); + // insert a new unique value + insertPrimaryKey( xFormProps, m_sFieldName ); + } + catch( com.sun.star.uno.Exception e ) + { + System.out.println(e); + e.printStackTrace(); + } + } + return true; + } + + /* ------------------------------------------------------------------ */ + public boolean approveRowSetChange( com.sun.star.lang.EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + // not interested in vetoing executions of the row set + return true; + } + /* ------------------------------------------------------------------ */ + // XEventListener overridables + /* ------------------------------------------------------------------ */ + public void disposing( EventObject aEvent ) + { + // not interested in + } +} + +/**************************************************************************/ +/** allows to generate unique keys for a field of a Form +*/ +public class KeyGenerator +{ + /* ------------------------------------------------------------------ */ + private KeyGeneratorForReset m_aResetKeyGenerator; + private KeyGeneratorForUpdate m_aUpdateKeyGenerator; + private boolean m_bResetListening; + private boolean m_bUpdateListening; + + private XPropertySet m_xForm; + + /* ------------------------------------------------------------------ */ + /** ctor + @param xForm + specified the form to operate on + @param sFieldName + specifies the field which's value should be manipulated + */ + public KeyGenerator( XPropertySet xForm, String sFieldName, + XComponentContext xCtx ) + { + m_xForm = xForm; + + DocumentHelper aDocument = DocumentHelper.getDocumentForComponent( xForm, xCtx ); + + m_aResetKeyGenerator = new KeyGeneratorForReset( sFieldName, aDocument.getCurrentView() ); + m_aUpdateKeyGenerator = new KeyGeneratorForUpdate( sFieldName ); + + m_bResetListening = m_bUpdateListening = false; + } + + /* ------------------------------------------------------------------ */ + /** stops any actions on the form + */ + public void stopGenerator( ) + { + XReset xFormReset = UNO.queryReset( m_xForm ); + xFormReset.removeResetListener( m_aResetKeyGenerator ); + + XRowSetApproveBroadcaster xFormBroadcaster = UnoRuntime.queryInterface( + XRowSetApproveBroadcaster.class, m_xForm ); + xFormBroadcaster.removeRowSetApproveListener( m_aUpdateKeyGenerator ); + + m_bUpdateListening = m_bResetListening = false; + } + + /* ------------------------------------------------------------------ */ + /** activates one of our two key generators + */ + public void activateKeyGenerator( boolean bGenerateOnReset ) + { + // for resets + XReset xFormReset = UNO.queryReset( m_xForm ); + // for approving actions + XRowSetApproveBroadcaster xFormBroadcaster = UnoRuntime.queryInterface( + XRowSetApproveBroadcaster.class, m_xForm ); + + if ( bGenerateOnReset ) + { + if ( !m_bResetListening ) + xFormReset.addResetListener( m_aResetKeyGenerator ); + if ( m_bUpdateListening ) + xFormBroadcaster.removeRowSetApproveListener( m_aUpdateKeyGenerator ); + + m_bUpdateListening = false; + m_bResetListening = true; + } + else + { + if ( m_bResetListening ) + xFormReset.removeResetListener( m_aResetKeyGenerator ); + if ( !m_bUpdateListening ) + xFormBroadcaster.addRowSetApproveListener( m_aUpdateKeyGenerator ); + + m_bResetListening = false; + m_bUpdateListening = true; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/ListSelectionValidator.java b/odk/examples/DevelopersGuide/Forms/ListSelectionValidator.java new file mode 100644 index 000000000..8a8909390 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/ListSelectionValidator.java @@ -0,0 +1,59 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +public class ListSelectionValidator extends ControlValidator +{ + /** Creates a new instance of ListSelectionValidator */ + public ListSelectionValidator() + { + } + + public String explainInvalid( Object Value ) + { + try + { + short[] selectionIndexes = (short[])Value; + if ( selectionIndexes.length > 2 ) + return "please 2 entries, at most"; + } + catch( java.lang.Exception e ) + { + return "oops. What's this?"; + } + return ""; + } + + public boolean isValid( Object Value ) + { + try + { + short[] selectionIndexes = (short[])Value; + if ( selectionIndexes.length > 2 ) + return false; + return true; + } + catch( java.lang.Exception e ) + { + } + return false; + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/Makefile b/odk/examples/DevelopersGuide/Forms/Makefile new file mode 100644 index 000000000..54cf7aad9 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/Makefile @@ -0,0 +1,196 @@ +#************************************************************************* +# +# The Contents of this file are made available subject to the terms of +# the BSD license. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of Sun Microsystems, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +#************************************************************************** + +# Builds the Forms example of the Developers Guide. + +PRJ=../../.. +SETTINGS=$(PRJ)/settings + +include $(SETTINGS)/settings.mk +include $(SETTINGS)/std.mk + +# Define non-platform/compiler specific settings +SAMPLE_NAME=FormsExamples +SAMPLE_CLASS_OUT=$(OUT_CLASS)/$(SAMPLE_NAME) +SAMPLE_GEN_OUT=$(OUT_MISC)/$(SAMPLE_NAME) + +APP1_NAME=DataAwareness +APP1_CLASS_OUT=$(SAMPLE_CLASS_OUT)/$(APP1_NAME) +APP1_JAR=$(SAMPLE_CLASS_OUT)/$(APP1_NAME).jar +APP2_NAME=ValueBinding +APP2_CLASS_OUT=$(SAMPLE_CLASS_OUT)/$(APP2_NAME) +APP2_JAR=$(SAMPLE_CLASS_OUT)/$(APP2_NAME).jar +APP3_NAME=SpreadsheetValueBinding +APP3_CLASS_OUT=$(SAMPLE_CLASS_OUT)/$(APP3_NAME) +APP3_JAR=$(SAMPLE_CLASS_OUT)/$(APP3_NAME).jar +APP4_NAME=ControlValidation +APP4_CLASS_OUT=$(SAMPLE_CLASS_OUT)/$(APP4_NAME) +APP4_JAR=$(SAMPLE_CLASS_OUT)/$(APP4_NAME).jar + +COMMON_CLASS_OUT = $(SAMPLE_CLASS_OUT)/common +COMMON_JAVAFILES = \ + ButtonOperator.java \ + ComponentTreeTraversal.java \ + ControlLock.java \ + DocumentHelper.java \ + DocumentType.java \ + DocumentViewHelper.java \ + FLTools.java \ + FormLayer.java \ + GridFieldValidator.java \ + InteractionRequest.java \ + KeyGenerator.java \ + SalesFilter.java \ + UNO.java \ + SpreadsheetView.java \ + WaitForInput.java \ + DocumentBasedExample.java \ + TableCellTextBinding.java \ + SpreadsheetDocument.java \ + NumericValidator.java \ + TextValidator.java \ + BooleanValidator.java \ + ListSelectionValidator.java \ + DateValidator.java \ + TimeValidator.java \ + ControlValidator.java \ + SingleControlValidation.java \ + HsqlDatabase.java \ + RowSet.java \ + URLHelper.java + +COMMON_CLASSFILES = $(patsubst %.java,$(COMMON_CLASS_OUT)/%.class,$(COMMON_JAVAFILES)) + +SDK_CLASSPATH = $(subst $(EMPTYSTRING) $(PATH_SEPARATOR),$(PATH_SEPARATOR),$(CLASSPATH)\ + $(PATH_SEPARATOR)$(SAMPLE_CLASS_OUT)\ + $(PATH_SEPARATOR)$(COMMON_CLASS_OUT)) + + +# Targets +.PHONY: ALL +ALL : \ + FormsExample + +include $(SETTINGS)/stdtarget.mk + +$(COMMON_CLASSFILES) : $(COMMON_JAVAFILES) + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(SDK_JAVAC) $(JAVAC_FLAGS) -classpath "$(SDK_CLASSPATH)" -d $(COMMON_CLASS_OUT) $^ + +# rule for client/example application manifest file +$(SAMPLE_GEN_OUT)/%.mf : + -$(MKDIR) $(subst /,$(PS),$(@D)) + @echo Main-Class: com.sun.star.lib.loader.Loader> $@ + $(ECHOLINE)>> $@ + @echo Name: com/sun/star/lib/loader/Loader.class>> $@ + @echo Application-Class: $*>> $@ + +$(APP1_CLASS_OUT)/$(APP1_NAME).class : $(APP1_NAME).java $(COMMON_CLASSFILES) + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(SDK_JAVAC) $(JAVAC_FLAGS) -classpath "$(SDK_CLASSPATH)" -d $(APP1_CLASS_OUT) $< + +$(APP2_CLASS_OUT)/$(APP2_NAME).class : $(APP2_NAME).java $(COMMON_CLASSFILES) + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(SDK_JAVAC) $(JAVAC_FLAGS) -classpath "$(SDK_CLASSPATH)" -d $(APP2_CLASS_OUT) $< + +$(APP3_CLASS_OUT)/$(APP3_NAME).class : $(APP3_NAME).java $(COMMON_CLASSFILES) + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(SDK_JAVAC) $(JAVAC_FLAGS) -classpath "$(SDK_CLASSPATH)" -d $(APP3_CLASS_OUT) $< + +$(APP4_CLASS_OUT)/$(APP4_NAME).class : $(APP4_NAME).java $(COMMON_CLASSFILES) + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(SDK_JAVAC) $(JAVAC_FLAGS) -classpath "$(SDK_CLASSPATH)" -d $(APP4_CLASS_OUT) $< + +$(APP1_JAR) : $(SAMPLE_GEN_OUT)/$(APP1_NAME).mf $(APP1_CLASS_OUT)/$(APP1_NAME).class $(COMMON_CLASSFILES) + -$(DEL) $(subst \\,\,$(subst /,$(PS),$@)) + -$(MKDIR) $(subst /,$(PS),$(@D)) + +$(SDK_JAR) cvfm $@ $< -C $(APP1_CLASS_OUT) . + +$(SDK_JAR) uvf $@ -C $(COMMON_CLASS_OUT) . + +$(SDK_JAR) uvf $@ $(SDK_JAVA_UNO_BOOTSTRAP_FILES) + +$(APP2_JAR) : $(SAMPLE_GEN_OUT)/$(APP2_NAME).mf $(APP2_CLASS_OUT)/$(APP2_NAME).class $(COMMON_CLASSFILES) + -$(DEL) $(subst \\,\,$(subst /,$(PS),$@)) + -$(MKDIR) $(subst /,$(PS),$(@D)) + +$(SDK_JAR) cvfm $@ $< -C $(APP2_CLASS_OUT) . + +$(SDK_JAR) uvf $@ -C $(COMMON_CLASS_OUT) . + +$(SDK_JAR) uvf $@ $(SDK_JAVA_UNO_BOOTSTRAP_FILES) + +$(APP3_JAR) : $(SAMPLE_GEN_OUT)/$(APP3_NAME).mf $(APP3_CLASS_OUT)/$(APP3_NAME).class $(COMMON_CLASSFILES) + -$(DEL) $(subst \\,\,$(subst /,$(PS),$@)) + -$(MKDIR) $(subst /,$(PS),$(@D)) + +$(SDK_JAR) cvfm $@ $< -C $(APP3_CLASS_OUT) . + +$(SDK_JAR) uvf $@ -C $(COMMON_CLASS_OUT) . + +$(SDK_JAR) uvf $@ $(SDK_JAVA_UNO_BOOTSTRAP_FILES) + +$(APP4_JAR) : $(SAMPLE_GEN_OUT)/$(APP4_NAME).mf $(APP4_CLASS_OUT)/$(APP4_NAME).class $(COMMON_CLASSFILES) + -$(DEL) $(subst \\,\,$(subst /,$(PS),$@)) + -$(MKDIR) $(subst /,$(PS),$(@D)) + +$(SDK_JAR) cvfm $@ $< -C $(APP4_CLASS_OUT) . + +$(SDK_JAR) uvf $@ -C $(COMMON_CLASS_OUT) . + +$(SDK_JAR) uvf $@ $(SDK_JAVA_UNO_BOOTSTRAP_FILES) + +FormsExample : $(APP1_JAR) $(APP2_JAR) $(APP3_JAR) $(APP4_JAR) + @echo -------------------------------------------------------------------------------- + @echo "$(QM)$(APP1_NAME)$(QM)" demonstrates various things around data aware controls. + @echo "$(QM)$(APP2_NAME)$(QM)" demonstrates the use of value bindings for form controls. + @echo "$(QM)$(APP3_NAME)$(QM)" demonstrates the usage of the com.sun.star.table.CellValueBinding service + @echo "$(QM)$(APP4_NAME)$(QM)" demonstrates the form control validation API + + @echo Please use one of the following commands to run an example: + @echo - + @echo $(MAKE) $(APP1_NAME).run + @echo $(MAKE) $(APP2_NAME).run + @echo $(MAKE) $(APP3_NAME).run + @echo $(MAKE) $(APP4_NAME).run + @echo - + @echo Note: The data awareness example needs a running data source with name + @echo $(SQM) $(SQM)"$(QM)OO_SDK_Demo_DB$(QM)". Make sure that you have created such a data source, + @echo - + @echo The document "$(QM)ProgrammaticScriptAssignment.odt$(QM)" demonstrates + @echo how you can programmatically create form controls, and associated + @echo scripts with certain events. + @echo - + @echo $(MAKE) ProgrammaticScriptAssignment.odt.load + @echo -------------------------------------------------------------------------------- + +ProgrammaticScriptAssignment.odt.load : $(COMP_REGISTERFLAG) + "$(OFFICE_PROGRAM_PATH)$(PS)soffice" $(basename $@) + +%.run: $(SAMPLE_CLASS_OUT)/%.jar + $(SDK_JAVA) -Dcom.sun.star.lib.loader.unopath="$(OFFICE_PROGRAM_PATH)" -jar $< + +.PHONY: clean +clean : + -$(DELRECURSIVE) $(subst /,$(PS),$(SAMPLE_CLASS_OUT)) + -$(DELRECURSIVE) $(subst /,$(PS),$(SAMPLE_GEN_OUT)) diff --git a/odk/examples/DevelopersGuide/Forms/NumericValidator.java b/odk/examples/DevelopersGuide/Forms/NumericValidator.java new file mode 100644 index 000000000..4df77af20 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/NumericValidator.java @@ -0,0 +1,77 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +public class NumericValidator extends ControlValidator +{ + + /** Creates a new instance of NumericValidator */ + public NumericValidator( ) + { + } + + public String explainInvalid( Object Value ) + { + try + { + double value = ((Double)Value).doubleValue(); + if ( Double.compare( Double.NaN, value ) == 0 ) + return "This is NotANumber"; + if ( !isProperRange( value ) ) + return "The value must be between 0 and 100"; + if ( !isProperDigitCount( value ) ) + return "The value must have at most one decimal digit"; + } + catch( java.lang.Exception e ) + { + return "This is no valid number"; + } + return ""; + } + + public boolean isValid( Object Value ) + { + try + { + double value = ((Double)Value).doubleValue(); + if ( Double.compare( Double.NaN, value ) == 0 ) + return false; + if ( !isProperRange( value ) ) + return false; + if ( !isProperDigitCount( value ) ) + return false; + return true; + } + catch( java.lang.Exception e ) + { + } + return false; + } + + private boolean isProperRange( double value) + { + return ( value >= 0 ) && ( value <= 100 ); + } + + private boolean isProperDigitCount( double value) + { + return ( Math.floor( value * 10 ) == value * 10 ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/ProgrammaticScriptAssignment.odt b/odk/examples/DevelopersGuide/Forms/ProgrammaticScriptAssignment.odt Binary files differnew file mode 100644 index 000000000..40b952d94 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/ProgrammaticScriptAssignment.odt diff --git a/odk/examples/DevelopersGuide/Forms/RowSet.java b/odk/examples/DevelopersGuide/Forms/RowSet.java new file mode 100644 index 000000000..93e62cacf --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/RowSet.java @@ -0,0 +1,283 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.XIndexAccess; +import com.sun.star.container.XNameAccess; +import com.sun.star.io.XInputStream; +import com.sun.star.sdbc.SQLException; +import com.sun.star.sdbc.XArray; +import com.sun.star.sdbc.XBlob; +import com.sun.star.sdbc.XClob; +import com.sun.star.sdbc.XRef; +import com.sun.star.sdbc.XRow; +import com.sun.star.sdbc.XRowSet; +import com.sun.star.sdbc.XRowSetListener; +import com.sun.star.sdbcx.XColumnsSupplier; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; +import com.sun.star.util.Date; +import com.sun.star.util.DateTime; +import com.sun.star.util.Time; + +public class RowSet implements XRowSet, XRow +{ + private XRowSet m_rowSet; + private XRow m_row; + private XPropertySet m_rowSetProps; + + public RowSet( XComponentContext _context, String _dataSource, int _commandType, String _command ) + { + try + { + m_rowSetProps = UnoRuntime.queryInterface( + XPropertySet.class, _context.getServiceManager().createInstanceWithContext( "com.sun.star.sdb.RowSet", _context ) ); + m_rowSetProps.setPropertyValue( "DataSourceName", _dataSource ); + m_rowSetProps.setPropertyValue( "CommandType", Integer.valueOf( _commandType ) ); + m_rowSetProps.setPropertyValue( "Command", _command ); + + m_rowSet = UnoRuntime.queryInterface( XRowSet.class, m_rowSetProps ); + m_row = UnoRuntime.queryInterface( XRow.class, m_rowSetProps ); + } + catch ( Exception e ) + { + e.printStackTrace(System.err); + throw new java.lang.InstantiationError(); + } + } + + // misc + public int getColumnCount() + { + XColumnsSupplier suppCols = UnoRuntime.queryInterface( + XColumnsSupplier.class, m_rowSet ); + XIndexAccess columns = UnoRuntime.queryInterface( + XIndexAccess.class, suppCols.getColumns() ); + return columns.getCount(); + } + + // XRowSet + public void execute() throws SQLException + { + m_rowSet.execute(); + } + + public void addRowSetListener( XRowSetListener _listener ) + { + m_rowSet.addRowSetListener( _listener ); + } + + public void removeRowSetListener( XRowSetListener _listener ) + { + m_rowSet.removeRowSetListener( _listener ); + } + + public boolean next() throws SQLException + { + return m_rowSet.next(); + } + + public boolean isBeforeFirst() throws SQLException + { + return m_rowSet.isBeforeFirst(); + } + + public boolean isAfterLast() throws SQLException + { + return m_rowSet.isAfterLast(); + } + + public boolean isFirst() throws SQLException + { + return m_rowSet.isFirst(); + } + + public boolean isLast() throws SQLException + { + return m_rowSet.isLast(); + } + + public void beforeFirst() throws SQLException + { + m_rowSet.beforeFirst(); + } + + public void afterLast() throws SQLException + { + m_rowSet.afterLast(); + } + + public boolean first() throws SQLException + { + return m_rowSet.first(); + } + + public boolean last() throws SQLException + { + return m_rowSet.last(); + } + + public int getRow() throws SQLException + { + return m_rowSet.getRow(); + } + + public boolean absolute(int i) throws SQLException + { + return m_rowSet.absolute(i); + } + + public boolean relative(int i) throws SQLException + { + return m_rowSet.relative(i); + } + + public boolean previous() throws SQLException + { + return m_rowSet.previous(); + } + + public void refreshRow() throws SQLException + { + m_rowSet.refreshRow(); + } + + public boolean rowUpdated() throws SQLException + { + return m_rowSet.rowUpdated(); + } + + public boolean rowInserted() throws SQLException + { + return m_rowSet.rowInserted(); + } + + public boolean rowDeleted() throws SQLException + { + return m_rowSet.rowDeleted(); + } + + // XRow + public Object getStatement() throws SQLException + { + return m_rowSet.getStatement(); + } + + public boolean wasNull() throws SQLException + { + return m_row.wasNull(); + } + + public String getString(int i) throws SQLException + { + return m_row.getString(i); + } + + public boolean getBoolean(int i) throws SQLException + { + return m_row.getBoolean(i); + } + + public byte getByte(int i) throws SQLException + { + return m_row.getByte(i); + } + + public short getShort(int i) throws SQLException + { + return m_row.getShort(i); + } + + public int getInt(int i) throws SQLException + { + return m_row.getInt(i); + } + + public long getLong(int i) throws SQLException + { + return m_row.getLong(i); + } + + public float getFloat(int i) throws SQLException + { + return m_row.getFloat(i); + } + + public double getDouble(int i) throws SQLException + { + return m_row.getDouble(i); + } + + public byte[] getBytes(int i) throws SQLException + { + return m_row.getBytes(i); + } + + public Date getDate(int i) throws SQLException + { + return m_row.getDate(i); + } + + public Time getTime(int i) throws SQLException + { + return m_row.getTime(i); + } + + public DateTime getTimestamp(int i) throws SQLException + { + return m_row.getTimestamp(i); + } + + public XInputStream getBinaryStream(int i) throws SQLException + { + return m_row.getBinaryStream(i); + } + + public XInputStream getCharacterStream(int i) throws SQLException + { + return m_row.getCharacterStream(i); + } + + public Object getObject(int i, XNameAccess xNameAccess) throws SQLException + { + return m_row.getObject(i, xNameAccess); + } + + public XRef getRef(int i) throws SQLException + { + return m_row.getRef(i); + } + + public XBlob getBlob(int i) throws SQLException + { + return m_row.getBlob(i); + } + + public XClob getClob(int i) throws SQLException + { + return m_row.getClob(i); + } + + public XArray getArray(int i) throws SQLException + { + return m_row.getArray(i); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/SalesFilter.java b/odk/examples/DevelopersGuide/Forms/SalesFilter.java new file mode 100644 index 000000000..753135bd3 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/SalesFilter.java @@ -0,0 +1,510 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import com.sun.star.uno.*; +import com.sun.star.beans.*; +import com.sun.star.form.*; +import com.sun.star.lang.*; +import com.sun.star.awt.*; + +import java.util.Calendar; +import java.util.GregorianCalendar; + +/**************************************************************************/ +/** helper class for filtering the sales form +*/ +class SalesFilter implements XActionListener, XPropertyChangeListener, XResetListener +{ + private DocumentHelper m_aDocument; + private XPropertySet m_xSalesForm; + + private XPropertySet m_xFilterList; + private XPropertySet m_xManualFilter; + private XPropertySet m_xApplyFilter; + + private boolean m_bSettingsDirty; + private boolean m_bSettingDate; + private boolean m_bAdjustingFilterList; + private short m_nPreviousFilterIndex; + private java.util.ArrayList m_aFilterDates; + + /* ------------------------------------------------------------------ */ + public SalesFilter( DocumentHelper aDocument, XPropertySet xSalesForm, + XPropertySet xFilterListBox, XPropertySet xManualFilterEdit, XPropertySet xStartFilterButton ) + { + m_aFilterDates = new java.util.ArrayList(); + m_bSettingsDirty = false; + m_bSettingDate = false; + m_bAdjustingFilterList = false; + m_nPreviousFilterIndex = -1; + initFilterDates(); + + + // remember the components + m_aDocument = aDocument; + m_xSalesForm = xSalesForm; + + m_xFilterList = xFilterListBox; + m_xManualFilter = xManualFilterEdit; + m_xApplyFilter = xStartFilterButton; + + try + { + + // init control models + m_xFilterList.setPropertyValue( "Dropdown", Boolean.TRUE ); + m_xFilterList.setPropertyValue( "LineCount", Short.valueOf( (short)11 ) ); + m_xFilterList.setPropertyValue( "StringItemList", new String[] { "ever (means no filter)", "this morning", "1 week ago", "1 month ago", "1 year ago", "<other>" } ); + m_xFilterList.setPropertyValue( "DefaultSelection", new short[] { (short)0 } ); + + m_xApplyFilter.setPropertyValue( "Label", "Apply Filter" ); + + updateFilterControl(); + updateApplyButton(); + + + // add as listener to the events which require action + + // want to know about changed selection + m_xFilterList.addPropertyChangeListener( "SelectedItems", this ); + m_xManualFilter.addPropertyChangeListener( "Date", this ); + + // want to know about the date field being reset + XReset xReset = UNO.queryReset( m_xManualFilter ); + xReset.addResetListener( this ); + + // for the button, we can add to the control only, not to the model + // - clicking a button is something which happens on the _control_. + DocumentViewHelper aView = m_aDocument.getCurrentView(); + XButton xButton = aView.getFormControl( m_xApplyFilter, XButton.class ); + xButton.addActionListener( this ); + } + catch ( com.sun.star.uno.Exception e ) + { + System.out.println(e); + e.printStackTrace(); + } + } + + /* ================================================================== + = helper + ================================================================== */ + /* ------------------------------------------------------------------ */ + private void initFilterDates() + { + m_aFilterDates.clear(); + java.util.Date aNowAndHere = new java.util.Date(); + aNowAndHere.setHours( 0 ); + aNowAndHere.setMinutes( 0 ); + aNowAndHere.setSeconds( 0 ); + + // for every list entry, we add a java.util.Date to m_aFilterDates indicating + // since when the sales should be listed + + // ever + m_aFilterDates.add( null ); + + // this morning + m_aFilterDates.add( aNowAndHere ); + + // one week ago + GregorianCalendar aCalendar = new GregorianCalendar( ); + aCalendar.setTime( aNowAndHere ); + aCalendar.add( Calendar.DATE, -7 ); + m_aFilterDates.add( aCalendar.getTime() ); + + // one month ago + aCalendar.setTime( aNowAndHere ); + aCalendar.add( Calendar.MONTH, -1 ); + m_aFilterDates.add( aCalendar.getTime() ); + + // one year ago + aCalendar.setTime( aNowAndHere ); + aCalendar.add( Calendar.YEAR, -1 ); + m_aFilterDates.add( aCalendar.getTime() ); + + // the custom date + m_aFilterDates.add( null ); + } + + /* ------------------------------------------------------------------ */ + /** translates a date from the AWT Toolkit format to a java.util.date, or + vice versa. + */ + private Object translateDate( Object aDate ) throws java.lang.Exception + { + Object aReturn = null; + + GregorianCalendar aCalDate = new GregorianCalendar(); + if ( aDate.getClass().equals( Class.forName( "java.util.Date" ) ) ) + { + aCalDate.setTime( (java.util.Date)aDate ); + + int nDate = aCalDate.get( Calendar.YEAR ); + nDate = nDate * 100 + aCalDate.get( Calendar.MONTH ) + 1; + nDate = nDate * 100 + aCalDate.get( Calendar.DAY_OF_MONTH ); + + aReturn = Integer.valueOf( nDate ); + } + else if ( aDate.getClass().equals( Class.forName( "java.lang.Integer" ) ) ) + { + int nToolkitDate = ((Integer)aDate).intValue(); + aCalDate.set( Calendar.DAY_OF_MONTH, ( nToolkitDate % 100 ) ); + nToolkitDate /= 100; + aCalDate.set( Calendar.MONTH, ( nToolkitDate % 100 ) - 1 ); + nToolkitDate /= 100; + aCalDate.set( Calendar.YEAR, ( nToolkitDate % 10000 ) ); + + // default the time + aCalDate.set( Calendar.HOUR_OF_DAY, 0 ); + aCalDate.set( Calendar.MINUTE, 0 ); + aCalDate.set( Calendar.SECOND, 0 ); + + aReturn = aCalDate.getTime(); + } + + return aReturn; + } + + /* ------------------------------------------------------------------ */ + /** translates the given date into the ODBC date notation, which then can be used + for setting a filter at a row set + */ + private String getOdbcDate( Object aDate ) throws java.lang.Exception + { + String sOdbcDate = ""; + if ( null != aDate ) + { + if ( !aDate.getClass().equals( Class.forName( "java.util.Date" ) ) ) + aDate = translateDate( aDate ); + + if ( aDate.getClass().equals( Class.forName( "java.util.Date" ) ) ) + { + GregorianCalendar aCal = new GregorianCalendar(); + aCal.setTime( (java.util.Date)aDate ); + + sOdbcDate += "{D '"; + sOdbcDate += (Integer.valueOf( aCal.get( Calendar.YEAR ) ) ).toString(); + sOdbcDate += "-"; + + int nMonth = aCal.get( Calendar.MONTH ) + 1; + if ( nMonth < 10 ) + sOdbcDate += "0"; + sOdbcDate += (Integer.valueOf( nMonth ) ).toString(); + sOdbcDate += "-"; + + int nDay = aCal.get( Calendar.DAY_OF_MONTH ); + if ( nDay < 10 ) + sOdbcDate += "0"; + sOdbcDate += (Integer.valueOf( nDay ) ).toString(); + sOdbcDate += "'}"; + } + } + return sOdbcDate; + } + + /* ------------------------------------------------------------------ */ + private void updateApplyButton() + { + try + { + m_xApplyFilter.setPropertyValue( "Enabled", Boolean.valueOf( m_bSettingsDirty ) ); + } + catch ( com.sun.star.uno.Exception e ) + { + System.out.println(e); + e.printStackTrace(); + } + } + + /* ------------------------------------------------------------------ */ + /** creates a normalized calendar object from the given java.util.Date + */ + private GregorianCalendar getCalendarObject( java.util.Date aDate ) + { + // the date part + GregorianCalendar aReturn = null; + if ( null != aDate ) + { + aReturn = new GregorianCalendar( ); + aReturn.setTime( aDate ); + + // normalize the time part + aReturn.set( Calendar.HOUR_OF_DAY, 0 ); + aReturn.set( Calendar.MINUTE, 0 ); + aReturn.set( Calendar.SECOND, 0 ); + } + + return aReturn; + } + + /* ------------------------------------------------------------------ */ + final private short getCurrentSelectedFilter( ) throws com.sun.star.uno.Exception + { + short[] aSelected = (short[])m_xFilterList.getPropertyValue( "SelectedItems" ); + if ( 0 < aSelected.length ) + return aSelected[0]; + return -1; + } + + /* ------------------------------------------------------------------ */ + /** checks if the given filter index refers to the "<other>" entry which + allows the user to manually enter a date + */ + final private boolean isManualFilter( short nFilterIndex ) + { + return ( 5 == nFilterIndex ); + } + + /* ------------------------------------------------------------------ */ + private void updateFilterControl() + { + try + { + if ( isManualFilter( m_nPreviousFilterIndex ) ) + { // previously, the "custom" filter date was selected + // -> remember the date entered + Object aDate = translateDate( m_xManualFilter.getPropertyValue( "Date" ) ); + m_aFilterDates.set( m_nPreviousFilterIndex, aDate ); + } + + // check the current selection + if ( !m_bAdjustingFilterList ) + { + m_nPreviousFilterIndex = getCurrentSelectedFilter( ); + + // custom filter? + boolean bCustomFilter = isManualFilter( m_nPreviousFilterIndex ); + m_xManualFilter.setPropertyValue( "Enabled", Boolean.valueOf( bCustomFilter ) ); + if ( bCustomFilter ) + m_aDocument.getCurrentView().grabControlFocus( m_xManualFilter ); + + m_bSettingDate = true; + Object aSelectedDateLimit = m_aFilterDates.get( m_nPreviousFilterIndex ); + if ( null != aSelectedDateLimit ) + { + // translate this date into one the AWT Toolkit understands + Integer aTKDate = (Integer)translateDate( aSelectedDateLimit ); + m_xManualFilter.setPropertyValue( "Date", aTKDate ); + } + else + m_xManualFilter.setPropertyValue( "Date", new Any( new Type(), null ) ); + m_bSettingDate = false; + } + } + catch ( java.lang.Exception e ) + { + System.out.println(e); + e.printStackTrace(); + } + } + + /* ------------------------------------------------------------------ */ + /** compares the date part of two calendars + <p>For some strange reason I do not understand, GregorianCalendar.equals( GregorianCalendar ) + seems to always return false, as well as . Thus here is a method which compare two calendars, + restricted to their date part</p> + */ + private boolean equalDate( Calendar aLHS, Calendar aRHS ) + { + if ( ( null == aLHS ) != ( null == aRHS ) ) + // only one of them is null + return false; + + if ( null == aLHS ) + // both are null + return true; + + return ( aLHS.get( Calendar.YEAR ) == aRHS.get( Calendar.YEAR ) ) + && ( aLHS.get( Calendar.MONTH ) == aRHS.get( Calendar.MONTH ) ) + && ( aLHS.get( Calendar.DAY_OF_MONTH ) == aRHS.get( Calendar.DAY_OF_MONTH ) ); + } + + /* ------------------------------------------------------------------ */ + /** adds the current user filter to the list of date filters + @return + the index of the newly added date filter in the filter list + */ + private short addCurrentFilter( ) throws java.lang.Exception + { + // the current string items + String[] aOldFilterItems = (String[])m_xFilterList.getPropertyValue( "StringItemList" ); + + // translate this into a vector - much more comfort to work with a vector than with an array... + java.util.ArrayList aFilterItems = new java.util.ArrayList(); + for ( int i=0; i<aOldFilterItems.length; ++i ) + aFilterItems.add( aOldFilterItems[i] ); + + // the currently entered user defined filter date + Object aDate = translateDate( m_xManualFilter.getPropertyValue( "Date" ) ); + GregorianCalendar aDateCal = getCalendarObject( (java.util.Date)aDate ); + // check if this date is already present in the list of user defined dates + for ( int i=0; i<m_aFilterDates.size(); ++i ) + { + if ( !isManualFilter( (short)i ) ) // do not compare with the manual filter + { + GregorianCalendar aCheckCal = getCalendarObject( (java.util.Date)m_aFilterDates.get( i ) ); + if ( equalDate( aDateCal, aCheckCal ) ) + return (short)i; + } + } + System.out.println( ); + + if ( aFilterItems.size() > 10 ) // (6 standard items + 5 user defined items) + { + // the first (and thus oldest) user defined item + aFilterItems.remove( 6 ); + // keep our date vector synchron + m_aFilterDates.remove( 6 ); + } + + // add the current user defined filter + aFilterItems.add( aDate.toString() ); + m_aFilterDates.add( aDate ); + + // write back the string item list + m_bAdjustingFilterList = true; + String[] aNewFilterItems = new String[ aFilterItems.size() ]; + for ( int i=0; i<aFilterItems.size(); ++i ) + aNewFilterItems[i] = (String)aFilterItems.get( i ); + m_xFilterList.setPropertyValue( "StringItemList", aNewFilterItems ); + m_bAdjustingFilterList = false; + + return (short)(aNewFilterItems.length - 1 ); + } + + /* ------------------------------------------------------------------ */ + private void executeCurrentFilter() + { + try + { + // we keep the date field consistent with whatever the user chooses in the + // list box, so just ask the field + Object aDate = translateDate( m_xManualFilter.getPropertyValue( "Date" ) ); + String sOdbcDate = getOdbcDate( aDate ); + + // if this filter was a manually entered filter, we add it to the filter list + // box to allow quick-select it later on. + if ( isManualFilter( getCurrentSelectedFilter() ) ) + { + short nNewUserDefinedFilterPos = addCurrentFilter(); + m_xFilterList.setPropertyValue( "SelectedItems", new short[] { nNewUserDefinedFilterPos } ); + } + + // set this as filter on the form + String sCompleteFilter = ""; + if ( ( null != sOdbcDate ) && ( 0 != sOdbcDate.length() ) ) + { + sCompleteFilter = "SALEDATE >= "; + sCompleteFilter += sOdbcDate; + } + m_xSalesForm.setPropertyValue( "Filter", sCompleteFilter ); + m_xSalesForm.setPropertyValue( "ApplyFilter", Boolean.TRUE ); + + // and reload the form + XLoadable xLoad = UnoRuntime.queryInterface( + XLoadable.class, m_xSalesForm ); + xLoad.reload(); + + m_aDocument.getCurrentView().grabControlFocus( m_xFilterList ); + } + catch ( java.lang.Exception e ) + { + System.out.println(e); + e.printStackTrace(); + } + } + + /* ================================================================== + = UNO callbacks + ================================================================== */ + /* ------------------------------------------------------------------ */ + // XActionListener overridables + /* ------------------------------------------------------------------ */ + public boolean approveReset( EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + return false; + // do not allow the date field to be reset - it would set its content + // to the current date + // Note that another possible solution would be to wait for the reset + // event and correct the value there + } + + /* ------------------------------------------------------------------ */ + public void resetted( EventObject aEvent ) throws com.sun.star.uno.RuntimeException + { + } + + /* ------------------------------------------------------------------ */ + // XActionListener overridables + /* ------------------------------------------------------------------ */ + public void actionPerformed( ActionEvent aEvent ) throws com.sun.star.uno.RuntimeException + { + executeCurrentFilter(); + + m_bSettingsDirty = false; + updateApplyButton(); + } + + /* ------------------------------------------------------------------ */ + // XItemListener overridables + /* ------------------------------------------------------------------ */ + public void propertyChange( PropertyChangeEvent aEvent ) throws com.sun.star.uno.RuntimeException + { + if ( aEvent.PropertyName.equals( "SelectedItems" ) ) + { + updateFilterControl(); + + m_bSettingsDirty = true; + updateApplyButton(); + } + else if ( aEvent.PropertyName.equals( "Date" ) && !m_bSettingDate ) + { + m_bSettingsDirty = true; + updateApplyButton(); + } + } + + /* ------------------------------------------------------------------ */ + // XEventListener overridables + /* ------------------------------------------------------------------ */ + public void disposing( EventObject aEvent ) + { + // not interested in + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/SingleControlValidation.java b/odk/examples/DevelopersGuide/Forms/SingleControlValidation.java new file mode 100644 index 000000000..719670031 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/SingleControlValidation.java @@ -0,0 +1,171 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +import com.sun.star.uno.*; +import com.sun.star.beans.*; +import com.sun.star.form.validation.*; + +public class SingleControlValidation implements XFormComponentValidityListener +{ + private DocumentHelper m_document; /// our current test document + private FormLayer m_formLayer; /// quick access to the form layer + + private XPropertySet m_inputField; + private XPropertySet m_inputLabel; + private XPropertySet m_statusField; + private XPropertySet m_explanationField; + private XValidator m_validator; + + /* ------------------------------------------------------------------ */ + public SingleControlValidation( DocumentHelper document, int columnPos, int rowPos, String formComponentService, XValidator validator ) + { + m_document = document; + m_validator = validator; + m_formLayer = new FormLayer( m_document ); + createControls( columnPos, rowPos, formComponentService, 1, 0 ); + } + + /* ------------------------------------------------------------------ */ + public SingleControlValidation( DocumentHelper document, int columnPos, int rowPos, String formComponentService, XValidator validator, int controlCount, int controlHeight ) + { + m_document = document; + m_validator = validator; + m_formLayer = new FormLayer( m_document ); + createControls( columnPos, rowPos, formComponentService, controlCount, controlHeight ); + } + + /* ------------------------------------------------------------------ */ + public XPropertySet getInputField() + { + return m_inputField; + } + + /* ------------------------------------------------------------------ */ + public void setExplanatoryText( String text ) + { + try + { + m_inputLabel.setPropertyValue( "Label", text ); + } + catch( com.sun.star.uno.Exception e ) + { + e.printStackTrace( System.err ); + } + } + + /* ------------------------------------------------------------------ */ + private void createControls( int columnPos, int rowPos, String formComponentService, int controlCount, int controlHeight ) + { + try + { + m_inputLabel = m_formLayer.createControlAndShape( "FixedText", columnPos, rowPos, 70, 12, null ); + m_inputLabel.setPropertyValue( "MultiLine", Boolean.TRUE ); + + com.sun.star.awt.FontDescriptor font = (com.sun.star.awt.FontDescriptor)m_inputLabel.getPropertyValue( "FontDescriptor" ); + font.Weight = com.sun.star.awt.FontWeight.BOLD; + m_inputLabel.setPropertyValue( "FontDescriptor", font ); + + if ( controlHeight == 0 ) + controlHeight = 6; + + int controlPos = rowPos + 12; + XPropertySet[] controls = new XPropertySet[ controlCount ]; + for ( int i = 0; i < controlCount; ++i, controlPos += controlHeight ) + { + controls[ i ] = m_formLayer.createControlAndShape( formComponentService, columnPos, controlPos, 25, controlHeight, null ); + controls[ i ].setPropertyValue( "Name", formComponentService ); + controls[ i ].setPropertyValue( "Tag", String.valueOf( i ) ); + + if ( controls[ i ].getPropertySetInfo().hasPropertyByName( "Border" ) ) + controls[ i ].setPropertyValue( "Border", Short.valueOf( (short)2 ) ); + + XValidatableFormComponent xComp = UnoRuntime.queryInterface( XValidatableFormComponent.class, + controls[ i ] ); + xComp.addFormComponentValidityListener( this ); + } + m_inputField = controls[ 0 ]; + + + controlPos += 4; + XPropertySet xLabel = m_formLayer.createControlAndShape( "FixedText", columnPos, controlPos, 70, 4, null ); + xLabel.setPropertyValue( "Label", "Status:" ); + controlPos += 4; + m_statusField = m_formLayer.createControlAndShape( "FixedText", columnPos, controlPos, 70, 4, null ); + m_statusField.setPropertyValue( "Label", "" ); + + + controlPos += 6; + xLabel = m_formLayer.createControlAndShape( "FixedText", columnPos, controlPos, 70, 4, null ); + xLabel.setPropertyValue( "Label", "Explanation for invalidity:" ); + controlPos += 4; + m_explanationField = m_formLayer.createControlAndShape( "FixedText", columnPos, controlPos, 70, 4, null ); + m_explanationField.setPropertyValue( "Label", "" ); + + XValidatable xValidatable = UnoRuntime.queryInterface( XValidatable.class, m_inputField ); + xValidatable.setValidator( m_validator ); + } + catch( java.lang.Exception e ) + { + e.printStackTrace( System.err ); + } + } + + /* ------------------------------------------------------------------ */ + /* XEventListener overridables */ + /* ------------------------------------------------------------------ */ + public void disposing( com.sun.star.lang.EventObject eventObject ) + { + // not interested in + } + + /* ------------------------------------------------------------------ */ + /* XFormComponentValidityListener overridables */ + /* ------------------------------------------------------------------ */ + public void componentValidityChanged( com.sun.star.lang.EventObject eventObject ) + { + try + { + if ( m_inputField.equals( eventObject.Source ) ) + { + XValidatableFormComponent xComp = UnoRuntime.queryInterface( XValidatableFormComponent.class, + eventObject.Source ); + // the current value + Object value = xComp.getCurrentValue(); + + // the current validity flag + boolean isValid = xComp.isValid(); + + m_statusField.setPropertyValue("Label", isValid ? "valid" : "invalid" ); + m_statusField.setPropertyValue( "TextColor", Integer.valueOf( isValid ? 0x008000 : 0x800000 ) ); + + String validityMessage = ""; + if ( !isValid ) + validityMessage = m_validator.explainInvalid( value ); + m_explanationField.setPropertyValue( "Label", validityMessage ); + } + } + catch( com.sun.star.uno.Exception e ) + { + e.printStackTrace( System.err ); + } + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/SpreadsheetDocument.java b/odk/examples/DevelopersGuide/Forms/SpreadsheetDocument.java new file mode 100644 index 000000000..b227b2d5f --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/SpreadsheetDocument.java @@ -0,0 +1,120 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +import com.sun.star.uno.*; +import com.sun.star.lang.XComponent; +import com.sun.star.table.XCellRange; +import com.sun.star.table.CellAddress; +import com.sun.star.table.CellRangeAddress; +import com.sun.star.container.XIndexAccess; +import com.sun.star.sheet.XSpreadsheetDocument; +import com.sun.star.beans.NamedValue; + +public class SpreadsheetDocument extends DocumentHelper +{ + /** Creates a new blank spreadsheet document */ + public SpreadsheetDocument( XComponentContext xCtx ) throws com.sun.star.uno.Exception + { + super( xCtx, implCreateBlankDocument( xCtx, "private:factory/scalc" ) ); + } + + public SpreadsheetDocument( XComponentContext xCtx, XComponent document ) + { + super( xCtx, document ); + } + + public XCellRange getSheet( int index ) throws com.sun.star.uno.Exception + { + XSpreadsheetDocument spreadsheetDoc = UnoRuntime.queryInterface( XSpreadsheetDocument.class, + m_documentComponent + ); + XIndexAccess sheets = UnoRuntime.queryInterface( XIndexAccess.class, + spreadsheetDoc.getSheets() + ); + return UnoRuntime.queryInterface( XCellRange.class, + sheets.getByIndex( index ) + ); + } + + /** creates a value binding for a given cell + */ + public com.sun.star.form.binding.XValueBinding createCellBinding( short sheet, short column, short row ) + { + return createCellBinding( sheet, column, row, false ); + } + + /** creates a value binding which can be used to exchange a list box selection <em>index</em> with a cell + */ + public com.sun.star.form.binding.XValueBinding createListIndexBinding( short sheet, short column, short row ) + { + return createCellBinding( sheet, column, row, true ); + } + + /** creates a value binding for a given cell, with or without support for integer value exchange + */ + private com.sun.star.form.binding.XValueBinding createCellBinding( short sheet, short column, short row, boolean supportIntegerValues ) + { + com.sun.star.form.binding.XValueBinding cellBinding = null; + try + { + CellAddress address = new CellAddress( sheet, column, row ); + Object[] initParam = new Object[] { new NamedValue( "BoundCell", address ) }; + cellBinding = UnoRuntime.queryInterface( + com.sun.star.form.binding.XValueBinding.class, + createInstanceWithArguments( + supportIntegerValues ? "com.sun.star.table.ListPositionCellBinding" + : "com.sun.star.table.CellValueBinding", + initParam + ) + ); + } + catch( com.sun.star.uno.Exception e ) + { + System.err.println( e ); + e.printStackTrace( System.err ); + } + return cellBinding; + } + + /** creates a source of list entries associated with a (one-column) cell range + */ + public com.sun.star.form.binding.XListEntrySource createListEntrySource( short sheet, short column, + short topRow, short bottomRow ) + { + com.sun.star.form.binding.XListEntrySource entrySource = null; + try + { + CellRangeAddress rangeAddress = new CellRangeAddress( sheet, column, + topRow, column, bottomRow ); + Object[] initParam = new Object[] { new NamedValue( "CellRange", rangeAddress ) }; + entrySource = UnoRuntime.queryInterface( + com.sun.star.form.binding.XListEntrySource.class, + createInstanceWithArguments( + "com.sun.star.table.CellRangeListSource", initParam ) ); + } + catch( com.sun.star.uno.Exception e ) + { + System.err.println( e ); + e.printStackTrace( System.err ); + } + return entrySource; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/SpreadsheetValueBinding.java b/odk/examples/DevelopersGuide/Forms/SpreadsheetValueBinding.java new file mode 100644 index 000000000..1f08f2e7e --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/SpreadsheetValueBinding.java @@ -0,0 +1,125 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +import com.sun.star.uno.UnoRuntime; + +import com.sun.star.beans.XPropertySet; +import com.sun.star.table.XCellRange; +import com.sun.star.text.XTextRange; +import com.sun.star.form.binding.XValueBinding; +import com.sun.star.form.binding.XBindableValue; +import com.sun.star.form.binding.XListEntrySource; +import com.sun.star.form.binding.XListEntrySink; + +public class SpreadsheetValueBinding extends DocumentBasedExample +{ + /** Creates a new instance of SpreadsheetValueBinding */ + public SpreadsheetValueBinding() + { + super( DocumentType.CALC ); + } + + /* ------------------------------------------------------------------ */ + @Override + protected void prepareDocument() throws com.sun.star.uno.Exception, java.lang.Exception + { + super.prepareDocument(); + + SpreadsheetDocument document = (SpreadsheetDocument)m_document; + + final short sheet = (short)0; + final short exchangeColumn = (short)1; // B + final short exchangeRow = (short)1; // 2 + final Integer backColor = Integer.valueOf( 0x00E0E0E0 ); + + + // a numeric control + XPropertySet numericControl = m_formLayer.insertControlLine( "NumericField", + "enter a value", "", 30 ); + numericControl.setPropertyValue( "ValueMin", Short.valueOf( (short)1 ) ); + numericControl.setPropertyValue( "ValueMax", Short.valueOf( (short)5 ) ); + numericControl.setPropertyValue( "Value", Short.valueOf( (short)1 ) ); + numericControl.setPropertyValue( "DecimalAccuracy", Short.valueOf( (short)0 ) ); + numericControl.setPropertyValue( "Spin", Boolean.TRUE ); + + // bind the control model to cell B2 + implBind( numericControl, document.createCellBinding( sheet, exchangeColumn, exchangeRow ) ); + + + // insert a list box + XPropertySet listBox = m_formLayer.insertControlLine( "ListBox", + "select an entry", "", 2, 40, 20 ); + listBox.setPropertyValue( "Dropdown", Boolean.FALSE ); + + // a list binding for cell range C1-C5 + final short listSourceSheet = (short)1; + final short column = (short)0; + final short topRow = (short)0; + final short bottomRow = (short)4; + XListEntrySource entrySource = document.createListEntrySource( + listSourceSheet, column, topRow, bottomRow ); + + // bind it to the list box + XListEntrySink consumer = UnoRuntime.queryInterface( + XListEntrySink.class, listBox ); + consumer.setListEntrySource( entrySource ); + + // and also put the list selection index into cell B2 + implBind( listBox, document.createListIndexBinding( sheet, exchangeColumn, exchangeRow ) ); + + + // fill the cells which we just bound the listbox to + XCellRange exchangeSheet = document.getSheet( listSourceSheet ); + String[] listContent = new String[] { "first", "second", "third", "forth", "fivth" }; + for ( short row = topRow; row <= bottomRow; ++row ) + { + XTextRange cellText = UnoRuntime.queryInterface( + XTextRange.class, exchangeSheet.getCellByPosition( column, row ) ); + cellText.setString( listContent[row] ); + } + + // some coloring + XPropertySet exchangeCell = UNO.queryPropertySet( + document.getSheet( sheet ).getCellByPosition( exchangeColumn, exchangeRow ) + ); + exchangeCell.setPropertyValue( "CellBackColor", backColor ); + numericControl.setPropertyValue( "BackgroundColor", backColor ); + listBox.setPropertyValue( "BackgroundColor", backColor ); + } + + /* ------------------------------------------------------------------ */ + private void implBind( XPropertySet controlModel, XValueBinding binding ) throws com.sun.star.form.binding.IncompatibleTypesException + { + XBindableValue bindable = UnoRuntime.queryInterface( + XBindableValue.class, controlModel + ); + bindable.setValueBinding( binding ); + } + + /* ------------------------------------------------------------------ */ + /** class entry point + */ + public static void main(String argv[]) throws java.lang.Exception + { + SpreadsheetValueBinding aSample = new SpreadsheetValueBinding(); + aSample.run( argv ); + } + } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/SpreadsheetView.java b/odk/examples/DevelopersGuide/Forms/SpreadsheetView.java new file mode 100644 index 000000000..63a8e6a98 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/SpreadsheetView.java @@ -0,0 +1,35 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +import com.sun.star.lang.*; +import com.sun.star.frame.*; + +public class SpreadsheetView extends DocumentViewHelper +{ + + /** Creates a new instance of SpreadsheetView */ + public SpreadsheetView( XMultiServiceFactory orb, DocumentHelper document, XController controller ) + { + super( orb, document, controller ); + } + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/TableCellTextBinding.java b/odk/examples/DevelopersGuide/Forms/TableCellTextBinding.java new file mode 100644 index 000000000..23a9e4226 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/TableCellTextBinding.java @@ -0,0 +1,199 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +import com.sun.star.uno.Type; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.table.XCell; +import com.sun.star.util.XModifyListener; +import com.sun.star.text.XTextRange; + +/** a value binding to be connected to a form control + + This binding synchronizes the text contained in a table cell (which you must + pass upon construction) to the text in an XBindableValue. + + Well, in real it does not synchronize both directions. The ValueBinding + service has not much room for own activity: It allows notification of changes + in the own value, and it allows external instances to set the current value. + + Note that we implement this binding as a separate thread, which is (more or + less permanently) polling for a new text at the cell. This is unfortunate, but + sadly the Writer table cells do not support actively notifying changes in their + content to other interested parties. +*/ +public class TableCellTextBinding + extends java.lang.Thread + implements com.sun.star.form.binding.XValueBinding, + com.sun.star.util.XModifyBroadcaster +{ + private XTextRange m_cellText; + private Object m_writeSignal; + private String m_newCellText; + private String m_lastKnownCellText; + private boolean m_haveNewCellText; + private java.util.List<XModifyListener> m_listeners; + + /** Creates a new instance of TableCellTextBinding */ + public TableCellTextBinding( XCell cell ) + { + m_cellText = UnoRuntime.queryInterface( XTextRange.class, cell ); + + m_newCellText = ""; + m_listeners = new java.util.LinkedList<XModifyListener>(); + + start(); + } + + /** retrieves the list of data types which this binding can exchange + */ + public com.sun.star.uno.Type[] getSupportedValueTypes() + { + try + { + // well, only strings here ... + return new Type[] { + getStringType() + }; + } + catch( java.lang.Exception e ) + { + } + return new Type[] { }; + } + + /** retrieves the current value + */ + public Object getValue(com.sun.star.uno.Type type) throws com.sun.star.form.binding.IncompatibleTypesException + { + if ( !type.equals( getStringType() ) ) + throw new com.sun.star.form.binding.IncompatibleTypesException(); + + return m_cellText.getString(); + } + + /** sets a new value + */ + public void setValue(Object obj) throws com.sun.star.form.binding.IncompatibleTypesException + { + String text; + try + { + text = (String)obj; + } + catch( java.lang.ClassCastException e ) + { + throw new com.sun.star.form.binding.IncompatibleTypesException(); + } + // remember the new text + synchronized( m_newCellText ) + { + m_newCellText = text; + m_haveNewCellText = true; + } + // and wake up the thread which is waiting for it + synchronized( m_writeSignal ) + { + m_writeSignal.notify(); + } + } + + /** determines whether a given value type is supported + */ + public boolean supportsType(com.sun.star.uno.Type type) + { + return type.equals( getStringType() ); + } + + /** retrieves the UNO type for the string class + */ + private static final Type getStringType() + { + return new com.sun.star.uno.Type( String.class ); + } + + /** runs the thread + */ + @Override + public void run() + { + try + { + m_writeSignal = new Object(); + while ( true ) + { + // go sleep a while + synchronized( m_writeSignal ) + { + m_writeSignal.wait( 200 ); + } + + // if there's new text in the control, propagate it to the cell + synchronized ( m_newCellText ) + { + if ( m_haveNewCellText ) + { + m_cellText.setString( m_newCellText ); + m_lastKnownCellText = m_newCellText; + } + m_haveNewCellText = false; + } + + // if there's new text in the cell, propagate it to the control + String currentCellText = m_cellText.getString(); + if ( !currentCellText.equals( m_lastKnownCellText ) ) + { + m_lastKnownCellText = currentCellText; + // notify the modification + synchronized( m_listeners ) + { + com.sun.star.lang.EventObject eventSource = new com.sun.star.lang.EventObject( this ); + + java.util.Iterator<XModifyListener> loop = m_listeners.iterator(); + while ( loop.hasNext() ) + { + loop.next().modified( eventSource ); + } + } + } + } + } + catch( java.lang.Exception e ) + { + e.printStackTrace(System.err); + } + } + + public void addModifyListener(com.sun.star.util.XModifyListener xModifyListener) + { + synchronized( m_listeners ) + { + m_listeners.add( xModifyListener ); + } + } + + public void removeModifyListener(com.sun.star.util.XModifyListener xModifyListener) + { + synchronized( m_listeners ) + { + m_listeners.remove( xModifyListener ); + } + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/TextValidator.java b/odk/examples/DevelopersGuide/Forms/TextValidator.java new file mode 100644 index 000000000..241bd8778 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/TextValidator.java @@ -0,0 +1,78 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +public class TextValidator extends ControlValidator +{ + + /** Creates a new instance of NumericValidator */ + public TextValidator( ) + { + } + + public String explainInvalid( Object Value ) + { + try + { + String value = (String)Value; + if ( containsZs( value ) ) + return "No Z's allowed here"; + if ( !isProperChunks( value ) ) + return "Need 3 * n characters"; + } + catch( java.lang.Exception e ) + { + return "ooops. Unknown error"; + } + return ""; + } + + public boolean isValid( Object Value ) + { + try + { + String value = (String)Value; + if ( containsZs( value ) ) + return false; + if ( !isProperChunks( value ) ) + return false; + return true; + } + catch( java.lang.Exception e ) + { + } + return false; + } + + private boolean isProperChunks( String value ) + { + return ( value.length() % 3 ) == 0; + } + + private boolean containsZs( String value ) + { + if ( ( value.indexOf( 'Z' ) != -1 ) + || ( value.indexOf( 'z' ) != -1 ) + ) + return true; + return false; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/TimeValidator.java b/odk/examples/DevelopersGuide/Forms/TimeValidator.java new file mode 100644 index 000000000..d5f1503d8 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/TimeValidator.java @@ -0,0 +1,83 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +public class TimeValidator extends ControlValidator +{ + + /** Creates a new instance of NumericValidator */ + public TimeValidator( ) + { + } + + public String explainInvalid( Object Value ) + { + try + { + if ( isVoid( Value ) ) + return "empty input"; + + com.sun.star.util.Time timeValue = (com.sun.star.util.Time)Value; + if ( isInvalidTime( timeValue ) ) + return "this is no valid time"; + if ( !isFullHour( timeValue ) ) + return "time must denote a full hour"; + } + catch( java.lang.Exception e ) + { + return "this is no valid time"; + } + return ""; + } + + public boolean isValid( Object Value ) + { + try + { + if ( isVoid( Value ) ) + return false; + + com.sun.star.util.Time timeValue = (com.sun.star.util.Time) + com.sun.star.uno.AnyConverter.toObject( + com.sun.star.util.Time.class, Value); + if ( isInvalidTime( timeValue ) ) + return false; + if ( !isFullHour( timeValue ) ) + return false; + return true; + } + catch( java.lang.Exception e ) + { + e.printStackTrace( System.err ); + } + return false; + } + + private boolean isInvalidTime( com.sun.star.util.Time timeValue ) + { + return ( timeValue.Hours == -1 ) && ( timeValue.Minutes == -1 ) && ( timeValue.Seconds == -1 ) && ( timeValue.NanoSeconds == -1 ); + } + + private boolean isFullHour( com.sun.star.util.Time timeValue ) + { + return ( timeValue.Minutes == 0 ) && ( timeValue.Seconds == 0 ) && ( timeValue.NanoSeconds == 0 ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/UNO.java b/odk/examples/DevelopersGuide/Forms/UNO.java new file mode 100644 index 000000000..f2e6fc611 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/UNO.java @@ -0,0 +1,89 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *************************************************************************/ + +import com.sun.star.uno.*; +import com.sun.star.beans.*; +import com.sun.star.awt.*; +import com.sun.star.container.*; +import com.sun.star.form.*; +import com.sun.star.lang.*; +import com.sun.star.sdb.*; + +public class UNO +{ + public static XPropertySet queryPropertySet( Object aObject ) + { + return UnoRuntime.queryInterface( XPropertySet.class, aObject ); + } + public static XControlModel queryControlModel( Object aObject ) + { + return UnoRuntime.queryInterface( XControlModel.class, aObject ); + } + public static XIndexContainer queryIndexContainer( Object aObject ) + { + return UnoRuntime.queryInterface( XIndexContainer.class, aObject ); + } + public static XReset queryReset( Object aObject ) + { + return UnoRuntime.queryInterface( XReset.class, aObject ); + } + public static XServiceInfo queryServiceInfo( Object aObject ) + { + return UnoRuntime.queryInterface( XServiceInfo.class, aObject ); + } + public static XColumn queryColumn( Object aObject ) + { + return UnoRuntime.queryInterface( XColumn.class, aObject ); + } + + public static XComponent queryComponent( Object aObject ) + { + return UnoRuntime.queryInterface( XComponent.class, aObject ); + } + + + +/* replace Foo with the identifier of your choice. + + Why does Java not have templates? + + public static XFoo queryFoo( Object aObject ) + { + return (XFoo)UnoRuntime.queryInterface( XFoo.class, aObject ); + } +*/ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/URLHelper.java b/odk/examples/DevelopersGuide/Forms/URLHelper.java new file mode 100644 index 000000000..d1d361676 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/URLHelper.java @@ -0,0 +1,65 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +import java.io.File; +import java.net.MalformedURLException; + +public class URLHelper +{ + /** + * Because the office need URLs for loading/saving documents + * we must convert used system paths. + * And java use another notation for file URLs ... correct it. + * + * @param aSystemPath + * represent the file in system notation + * + * @return [String] + * a file url which represent the given system path + */ + public static String getFileURLFromSystemPath( File aSystemPath ) + { + String sFileURL = null; + try + { + sFileURL = aSystemPath.toURI().toURL().toString(); + } + catch( MalformedURLException exWrong ) + { + sFileURL = null; + } + + // problem of java: file URL's are coded with 1 slash instead of 2 or 3 ones! + // => correct this problem first, otherwise office can't use these URL's + if( + (sFileURL != null ) && + (sFileURL.startsWith("file:/") == true ) && + (sFileURL.startsWith("file://") == false) + ) + { + StringBuffer sWorkBuffer = new StringBuffer(sFileURL); + sWorkBuffer.insert(6,"//"); + sFileURL = sWorkBuffer.toString(); + } + + return sFileURL; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/ValueBinding.java b/odk/examples/DevelopersGuide/Forms/ValueBinding.java new file mode 100644 index 000000000..273f04cda --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/ValueBinding.java @@ -0,0 +1,82 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +import com.sun.star.uno.UnoRuntime; + +import com.sun.star.beans.XPropertySet; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XText; +import com.sun.star.text.XTextTable; +import com.sun.star.text.XTextCursor; +import com.sun.star.form.binding.XValueBinding; +import com.sun.star.form.binding.XBindableValue; + +public class ValueBinding extends DocumentBasedExample +{ + /** Creates a new instance of ValueBinding */ + public ValueBinding() + { + super( DocumentType.WRITER ); + } + + /* ------------------------------------------------------------------ */ + @Override + protected void prepareDocument() throws com.sun.star.uno.Exception, java.lang.Exception + { + super.prepareDocument(); + + // insert a table with exactly one cell. The content of this table will be synced with + // the content of a form control + XTextDocument textDoc = UnoRuntime.queryInterface( XTextDocument.class, m_document.getDocument() ); + XText documentText = textDoc.getText(); + XTextCursor textCursor = documentText.createTextCursor(); + documentText.insertString( textCursor, "Below, there's a table cell, and a text field. ", false ); + documentText.insertString( textCursor, "Both are linked via an external value binding.\n", false ); + documentText.insertString( textCursor, "That means that anything you insert into the table cell is reflected in the ", false ); + documentText.insertString( textCursor, "text field, and vice versa.\n", false ); + + XTextTable table = UnoRuntime.queryInterface( XTextTable.class, + m_document.createInstance( "com.sun.star.text.TextTable" ) + ); + table.initialize( 1, 1 ); + documentText.insertTextContent( textCursor, table, false ); + + // insert our sample control + XPropertySet textControl = m_formLayer.insertControlLine( "DatabaseTextField", "enter some text", "", 30 ); + + // create a value binding for the first cell of the table + XValueBinding cellBinding = new TableCellTextBinding( table.getCellByName( "A1" ) ); + // and bind it to the control + XBindableValue bindable = UnoRuntime.queryInterface( + XBindableValue.class, textControl + ); + bindable.setValueBinding( cellBinding ); + } + + /* ------------------------------------------------------------------ */ + /** class entry point + */ + public static void main(String argv[]) throws java.lang.Exception + { + ValueBinding aSample = new ValueBinding(); + aSample.run( argv ); + } + } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/odk/examples/DevelopersGuide/Forms/WaitForInput.java b/odk/examples/DevelopersGuide/Forms/WaitForInput.java new file mode 100644 index 000000000..e5891ada4 --- /dev/null +++ b/odk/examples/DevelopersGuide/Forms/WaitForInput.java @@ -0,0 +1,58 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +class WaitForInput extends java.lang.Thread +{ + private Object m_aToNotify; + private boolean m_bDone; + + public WaitForInput( Object aToNotify ) + { + m_aToNotify = aToNotify; + m_bDone = false; + } + + public boolean isDone() + { + return m_bDone; + } + + @Override + public void run() + { + try + { + System.out.println( "\npress 'enter' to exit demo" ); + System.in.read(); + + m_bDone = true; + // notify that the user pressed the key + synchronized (m_aToNotify) + { + m_aToNotify.notify(); + } + } + catch( java.lang.Exception e ) + { + // not really interested in + System.err.println( e ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |