From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001
From: Daniel Baumann
Date: Sat, 27 Apr 2024 18:51:28 +0200
Subject: Adding upstream version 1:7.0.4.
Signed-off-by: Daniel Baumann
---
.../DevelopersGuide/Forms/BooleanValidator.java | 84 ++
.../DevelopersGuide/Forms/ButtonOperator.java | 219 +++++
.../Forms/ComponentTreeTraversal.java | 92 ++
.../DevelopersGuide/Forms/ControlLock.java | 223 +++++
.../DevelopersGuide/Forms/ControlValidation.java | 85 ++
.../DevelopersGuide/Forms/ControlValidator.java | 52 ++
.../DevelopersGuide/Forms/DataAwareness.java | 940 +++++++++++++++++++++
.../DevelopersGuide/Forms/DateValidator.java | 91 ++
.../Forms/DocumentBasedExample.java | 219 +++++
.../DevelopersGuide/Forms/DocumentHelper.java | 306 +++++++
.../DevelopersGuide/Forms/DocumentType.java | 40 +
.../DevelopersGuide/Forms/DocumentViewHelper.java | 215 +++++
odk/examples/DevelopersGuide/Forms/FLTools.java | 216 +++++
odk/examples/DevelopersGuide/Forms/FormLayer.java | 272 ++++++
.../DevelopersGuide/Forms/GridFieldValidator.java | 174 ++++
.../DevelopersGuide/Forms/HsqlDatabase.java | 184 ++++
.../DevelopersGuide/Forms/InteractionRequest.java | 71 ++
.../DevelopersGuide/Forms/KeyGenerator.java | 434 ++++++++++
.../Forms/ListSelectionValidator.java | 59 ++
odk/examples/DevelopersGuide/Forms/Makefile | 196 +++++
.../DevelopersGuide/Forms/NumericValidator.java | 77 ++
.../Forms/ProgrammaticScriptAssignment.odt | Bin 0 -> 19198 bytes
odk/examples/DevelopersGuide/Forms/RowSet.java | 283 +++++++
.../DevelopersGuide/Forms/SalesFilter.java | 510 +++++++++++
.../Forms/SingleControlValidation.java | 171 ++++
.../DevelopersGuide/Forms/SpreadsheetDocument.java | 120 +++
.../Forms/SpreadsheetValueBinding.java | 125 +++
.../DevelopersGuide/Forms/SpreadsheetView.java | 35 +
.../Forms/TableCellTextBinding.java | 199 +++++
.../DevelopersGuide/Forms/TextValidator.java | 78 ++
.../DevelopersGuide/Forms/TimeValidator.java | 83 ++
odk/examples/DevelopersGuide/Forms/UNO.java | 89 ++
odk/examples/DevelopersGuide/Forms/URLHelper.java | 65 ++
.../DevelopersGuide/Forms/ValueBinding.java | 82 ++
.../DevelopersGuide/Forms/WaitForInput.java | 58 ++
35 files changed, 6147 insertions(+)
create mode 100644 odk/examples/DevelopersGuide/Forms/BooleanValidator.java
create mode 100644 odk/examples/DevelopersGuide/Forms/ButtonOperator.java
create mode 100644 odk/examples/DevelopersGuide/Forms/ComponentTreeTraversal.java
create mode 100644 odk/examples/DevelopersGuide/Forms/ControlLock.java
create mode 100644 odk/examples/DevelopersGuide/Forms/ControlValidation.java
create mode 100644 odk/examples/DevelopersGuide/Forms/ControlValidator.java
create mode 100644 odk/examples/DevelopersGuide/Forms/DataAwareness.java
create mode 100644 odk/examples/DevelopersGuide/Forms/DateValidator.java
create mode 100644 odk/examples/DevelopersGuide/Forms/DocumentBasedExample.java
create mode 100644 odk/examples/DevelopersGuide/Forms/DocumentHelper.java
create mode 100644 odk/examples/DevelopersGuide/Forms/DocumentType.java
create mode 100644 odk/examples/DevelopersGuide/Forms/DocumentViewHelper.java
create mode 100644 odk/examples/DevelopersGuide/Forms/FLTools.java
create mode 100644 odk/examples/DevelopersGuide/Forms/FormLayer.java
create mode 100644 odk/examples/DevelopersGuide/Forms/GridFieldValidator.java
create mode 100644 odk/examples/DevelopersGuide/Forms/HsqlDatabase.java
create mode 100644 odk/examples/DevelopersGuide/Forms/InteractionRequest.java
create mode 100644 odk/examples/DevelopersGuide/Forms/KeyGenerator.java
create mode 100644 odk/examples/DevelopersGuide/Forms/ListSelectionValidator.java
create mode 100644 odk/examples/DevelopersGuide/Forms/Makefile
create mode 100644 odk/examples/DevelopersGuide/Forms/NumericValidator.java
create mode 100644 odk/examples/DevelopersGuide/Forms/ProgrammaticScriptAssignment.odt
create mode 100644 odk/examples/DevelopersGuide/Forms/RowSet.java
create mode 100644 odk/examples/DevelopersGuide/Forms/SalesFilter.java
create mode 100644 odk/examples/DevelopersGuide/Forms/SingleControlValidation.java
create mode 100644 odk/examples/DevelopersGuide/Forms/SpreadsheetDocument.java
create mode 100644 odk/examples/DevelopersGuide/Forms/SpreadsheetValueBinding.java
create mode 100644 odk/examples/DevelopersGuide/Forms/SpreadsheetView.java
create mode 100644 odk/examples/DevelopersGuide/Forms/TableCellTextBinding.java
create mode 100644 odk/examples/DevelopersGuide/Forms/TextValidator.java
create mode 100644 odk/examples/DevelopersGuide/Forms/TimeValidator.java
create mode 100644 odk/examples/DevelopersGuide/Forms/UNO.java
create mode 100644 odk/examples/DevelopersGuide/Forms/URLHelper.java
create mode 100644 odk/examples/DevelopersGuide/Forms/ValueBinding.java
create mode 100644 odk/examples/DevelopersGuide/Forms/WaitForInput.java
(limited to 'odk/examples/DevelopersGuide/Forms')
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 m_aButtons;
+
+ /* ------------------------------------------------------------------ */
+ /** ctor
+ */
+ public ButtonOperator( XComponentContext xCtx, DocumentHelper aDocument, XPropertySet _form )
+ {
+ m_componentContext = xCtx;
+ m_aDocument = aDocument;
+ m_form = _form;
+ m_aButtons = new ArrayList();
+ }
+
+ /* ------------------------------------------------------------------ */
+ 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.
+
+ The default implementation checks if the container given is a grid
+ control model or a FormComponents
+ instance.
+ */
+ 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 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.
+ 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.
+*/
+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
+ If the control models are really locked depends on the current
+ record of the form: on the insert row, controls are never locked.
+ */
+ 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 = "";
+ 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 = "";
+ 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.
+
+ 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...
+ */
+ 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 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
+ 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
+ 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=;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 if the user pressed a key on the console,
+ 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
+ * @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 DrawPage 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 get( Class 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
+ URL::Complete 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 getFormControl( Object aModel, Class 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 fallback to the component name
+ sLabel = getName( aFormComponent );
+ }
+ }
+
+ return sLabel;
+ }
+
+
+
+ /* ------------------------------------------------------------------ */
+ /** retrieves the parent of the given object
+ */
+ private static T getParent( Object aComponent, Class 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 getModel( Object aControl, Class 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.
+ 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.
+ */
+ public static String classifyFormComponentType( XPropertySet xComponent ) throws com.sun.star.uno.Exception
+ {
+ String sType = "";
+
+ 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
+
+ Note that control 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.
+
+
+ @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
+
+ Note that control 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.
+
+
+ @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.
+
+ 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.
+
+ @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; iActually, the mechanism for validating the field is not restricted to
+ grid control fields. Instead, it can be used for any bound controls.
+*/
+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 m_aContinuations;
+
+ /* ------------------------------------------------------------------ */
+ public InteractionRequest( Object aRequest )
+ {
+ m_aRequest = aRequest;
+ m_aContinuations = new ArrayList();
+ }
+
+
+
+ /* ------------------------------------------------------------------ */
+ 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.
+
+ This method works for forms based directly on tables, and for forms based on statements, which
+ themself are based on one table.
+ Everything else (especially forms based on queries) is not yet implemented.
+ */
+ 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.
+ 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 SELECT
statement below accordingly.
+
+ @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 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
new file mode 100644
index 000000000..40b952d94
Binary files /dev/null and b/odk/examples/DevelopersGuide/Forms/ProgrammaticScriptAssignment.odt differ
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", "" } );
+ 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 "" 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
+ 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
+ */
+ 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 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; iindex 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 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();
+
+ 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 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: */
--
cgit v1.2.3