コード例 #1
0
ファイル: QCaSpinBox.cpp プロジェクト: boiarino17/epics
/*!
    Act on a connection change.
    Change how the label looks and change the tool tip
    This is the slot used to recieve connection updates from a QCaObject based class.
 */
void QCaSpinBox::connectionChanged( QCaConnectionInfo& connectionInfo )
{
    /// If connected, enable the widget if the QCa enabled property is true
    if( connectionInfo.isChannelConnected() )
    {
        isConnected = true;
        updateToolTipConnection( isConnected );

        if( localEnabled )
            QWidget::setEnabled( true );
    }

    /// If disconnected always disable the widget.
    else
    {
        isConnected = false;
        updateToolTipConnection( isConnected );

        QWidget::setEnabled( false );
    }

    /// ??? not sure if this is right. Added as the record type was comming back as GENERIC::UNKNOWN deep in the write
    /// Start a single shot read if the channel is up (ignore channel down),
    /// This will allow initialisation of the widget using info from the database.
    /// If subscribing, then an update will occur without having to initiated one here.
    /// Note, channel up implies link up
    /// Note, even though there is nothing to do to initialise the spin box if not subscribing, an
    /// initial sing shot read is still performed to ensure we have valid information about the
    /// variable when it is time to do a write.
    if( connectionInfo.isChannelConnected() && !subscribe )
    {
        QCaInteger* qca = (QCaInteger*)getQcaItem(0);
        qca->singleShotRead();
    }
}
コード例 #2
0
void QEGenericButton::userReleased()
{
    // Do nothing if not acting on button release, or user confirmation required but not given, or password required but not given
    if( !writeOnRelease ||  !confirmAction() || !checkPassword() )
        return;

    // Determine the string to write
    QString writeText = substituteThis( releaseText );

    // Emit a 'released' signal
    emitReleased( writeText.toInt() );

    // Get the variable to write to
    QEString *qca = (QEString*)getQcaItem(0);

    // If a QCa object is present (if there is a variable to write to) then write the value
    if( qca )
    {
        QString error;
        if( !qca->writeString( writeText, error ) )
        {
            QMessageBox::warning( (QWidget*)getButtonQObject(), QString( "Write failed" ), error, QMessageBox::Cancel );
        }
    }
}
コード例 #3
0
ファイル: QELineEdit.cpp プロジェクト: rorydog1/epics
// Wite the given value to the associated channel.
//
bool QELineEdit::writeData (const QVariant & value, QString& message)
{
    QEString *qca = dynamic_cast <QEString*> ( getQcaItem(0) );

    if( qca ) {
       return qca->writeString( value.toString (), message);
    } else {
        message = "null qca object";
        return false;
    }
}
コード例 #4
0
// Write a value immedietly.
// Used when writeOnChange is false
// (widget will never write due to the user pressing return or leaving the widget)
void QESpinBox::writeNow()
{
    // Get the variable to write to
    QEFloating* qca = (QEFloating*)getQcaItem(0);

    // If a QCa object is present (if there is a variable to write to)
    // then write the value
    if( qca )
    {
        // Write the value
        qca->writeFloating( value() );
    }
}
コード例 #5
0
ファイル: QCaLineEdit.cpp プロジェクト: emayssat/sandbox
/*!
    The user has pressed return.
    Note, it doesn't matter if the user presses return and both this function
    AND userReturnPressed() is called since setText is called in each to clear
    the 'isModified' flag. So, the first called will perform the write, the
    second (if any) will do nothing.
*/
void QCaLineEdit::userReturnPressed() {

    /// Get the variable to write to
    QCaString *qca = (QCaString*)getQcaItem(0);

    /// If a QCa object is present (if there is a variable to write to)
    /// and the object is set up to write when the user presses return
    /// then write the value.
    /// Note, write even if the value has not changed (isModified() is not checked)

    if( qca && writeOnEnter )
    {
        writeValue( qca, text() );
    }
}
コード例 #6
0
ファイル: QCaSpinBox.cpp プロジェクト: boiarino17/epics
/*!
    The user has changed the spin box.
*/
void QCaSpinBox::userValueChanged( int value ) {
    // If the user is changing the value, write it.
    // Note, the spin box does not appear to have a signal that distinguishes between user changes and programatic changes
    if( !programaticValueChange )
    {
        /// Get the variable to write to
        QCaInteger* qca = (QCaInteger*)getQcaItem(0);

        /// If a QCa object is present (if there is a variable to write to)
        /// then write the value
        if( qca ) {
            qca->writeInteger( (long)value );
        }
    }
}
コード例 #7
0
ファイル: QCaLineEdit.cpp プロジェクト: emayssat/sandbox
/*!
    The user has 'finished editing' such as pressed return/enter or moved
    focus from the object.
    Note, it doesn't matter if the user presses return and both this function
    AND userReturnPressed() is called since setText is called in each to clear
    the 'isModified' flag. So, the first called will perform the write, the
    second (if any) will do nothing.
*/
void QCaLineEdit::userEditingFinished() {

    /// If no changes were made by the user, do nothing
    if( !isModified() )
        return;

    /// Get the variable to write to
    QCaString *qca = (QCaString*)getQcaItem(0);

    /// If a QCa object is present (if there is a variable to write to)
    /// and the object is set up to write when the user changes focus away from the object
    /// and the text has actually changed
    /// then write the value
    if( qca && writeOnLoseFocus )
    {
        writeValue( qca, text() );
    }

    /// If, for what ever reason, the value has been changed by the user but not but not written
    /// check with the user what to do about it.
    else
    {
        int confirm = QMessageBox::warning( this, "Value changed", "You altered a value but didn't write it.\nDo you want to write this value?",
                                            QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::No );

        switch( confirm )
        {
            /// Write the value
            case QMessageBox::Yes:
                if( qca )
                    writeValue( qca, text() );
                break;

            /// Abort the write, revert to latest value
            case QMessageBox::No:
                setText( lastValue );       /// Note, also clears 'isModified' flag
                break;

            /// Don't write the value, move back to the field being edited
            case QMessageBox::Cancel:
                setFocus();
                break;
        }
    }
}
コード例 #8
0
// Write a value immedietly.
// Used when writeOnChange is false
// (widget will never write due to the user pressing return or leaving the widget)
void QESlider::writeNow()
{
    // Get the variable to write to
    QEFloating* qca = (QEFloating*)getQcaItem(0);

    // If a QCa object is present (if there is a variable to write to)
    // then write the value
    if( qca )
    {
        // Attempt to write the data if the destination data type is known.
        // It is not known until a connection is established.
        if( qca->dataTypeKnown() )
        {
            double dd = value()/scale;
            qDebug() << dd;
            currentValue = (value()/scale)+offset;
            qca->writeFloating( currentValue );
        }
    }
}
コード例 #9
0
/*
    Pass the update straight on to the SpinBox unless the user is changing it.
    Note, it would not be common to have a user editing a regularly updating
    value. However, this scenario should be allowed for. A reasonable reason
    for a user modified value to update on a gui is if is is written to by
    another user on another gui.
    This is the slot used to recieve data updates from a QCaObject based class.
    This is the slot used to recieve data updates from a QCaObject based class.
*/
void QESpinBox::setValueIfNoFocus( const double& value, QCaAlarmInfo& alarmInfo, QCaDateTime&, const unsigned int& ) {

    // Set the limits and step size
    QEFloating* qca = (QEFloating*)getQcaItem(0);
    double upper = qca->getControlLimitUpper();
    double lower = qca->getControlLimitLower();
    if( upper != lower)
    {
        setMaximum( qca->getControlLimitUpper() );
        setMinimum( qca->getControlLimitLower() );
    }
    setDecimalsFromPrecision( qca );
    setSuffixEgu( qca );

    // Do nothing more if doing a single shot read (done when not subscribing to get range values)
    if( ignoreSingleShotRead )
    {
        ignoreSingleShotRead = false;
        return;
    }

    // Signal a database value change to any Link widgets
    emit dbValueChanged( value );

    // Save the last database value
    lastValue = value;

    // Update the spin box only if the user is not interacting with the object.
    if( !hasFocus() ) {
        // Update the spin box
        programaticValueChange = true;
        setValue( value );
        programaticValueChange = false;

        // Note the last value seen by the user
        lastUserValue = text();
    }

    // Invoke common alarm handling processing.
    processAlarmInfo( alarmInfo );
}
コード例 #10
0
/*
    The user has changed the spin box.
*/
void QESpinBox::userValueChanged( double value )
{
    // If the user is not changing the value, or not writing on change, do nothing
    if( programaticValueChange || !writeOnChange )
    {
        return;
    }

    // Get the variable to write to
    QEFloating* qca = (QEFloating*)getQcaItem(0);

    // If a QCa object is present (if there is a variable to write to)
    // then write the value
    if( qca ) {
        // Write the value
        qca->writeFloating( value );

        // Manage notifying user changes
        emit userChange( text(), lastUserValue, QString("%1").arg( lastValue ) );
    }
}
コード例 #11
0
ファイル: QEGenericEdit.cpp プロジェクト: rorydog1/epics
//------------------------------------------------------------------------------
// Write a value immediately.
// Used when writeOnLoseFocus, writeOnEnter, writeOnFinish are all false
// (widget will never write due to the user pressing return or leaving the widget)
//
void QEGenericEdit::writeNow ()
{
    // If not connected, do nothing
    if( !isConnected )
    {
        return;
    }

    // Get the variable to write to
   qcaobject::QCaObject *qca = getQcaItem(0);

   // If a QCa object is present (if there is a variable to write to)
   // and is of the corect type then write the value.
   //
   if ( qca ) {
      // Invokes a whole bunch of dialog logic, but eventually calls writeData.
      // Note: getValue is a dispatching hook procedure.
      //
      writeValue( qca, getValue () );
   }
}
コード例 #12
0
ファイル: QEGenericEdit.cpp プロジェクト: rorydog1/epics
//------------------------------------------------------------------------------
// The user has pressed return/enter. (Not write when user enters the widget)
// Note, it doesn't matter if the user presses return and both this function
// AND userReturnPressed() is called since setText is called in each to clear
// the 'isModified' flag. So, the first called will perform the write, the
// second (if any) will do nothing.
//
void QEGenericEdit::userReturnPressed()
{
    // If not connected, do nothing
    if( !isConnected )
    {
        return;
    }

    // Get the variable to write to
    qcaobject::QCaObject *qca = getQcaItem(0);

    // If a QCa object is present (if there is a variable to write to)
    // and the object is set up to write when the user presses return
    // then write the value.
    // Note, write even if the value has not changed (isModified() is not checked)

    if( qca && writeOnEnter )
    {
       // Note: getValue is a dispatching hook procedure.
       writeValue( qca, getValue () );
    }
}
コード例 #13
0
/*
    Act on a connection change.
    Change how the label looks and change the tool tip
    This is the slot used to recieve connection updates from a QCaObject based class.
 */
void QESpinBox::connectionChanged( QCaConnectionInfo& connectionInfo )
{
    // Note the connected state
    isConnected = connectionInfo.isChannelConnected();

    // Display the connected state
    updateToolTipConnection( isConnected );
    updateConnectionStyle( isConnected );

    // !!! ??? not sure if this is right. Added as the record type was comming back as GENERIC::UNKNOWN deep in the write
    // Start a single shot read if the channel is up (ignore channel down),
    // This will allow initialisation of the widget using info from the database.
    // If subscribing, then an update will occur without having to initiated one here.
    // Note, channel up implies link up
    // Note, even though there is nothing to do to initialise the spin box if not subscribing, an
    // initial sing shot read is still performed to ensure we have valid information about the
    // variable when it is time to do a write.
    if( isConnected && !subscribe )
    {
        QEFloating* qca = (QEFloating*)getQcaItem(0);
        qca->singleShotRead();
        ignoreSingleShotRead = true;
    }
}
コード例 #14
0
/*
    The user has modified the slider position.
    This will occur as the user slides the slider if tracking is enabled,
    or when the user completes sliding if tracking is not enabled.
*/
void QESlider::userValueChanged( const int &value) {

    // If the change is due to an update (and not the user)
    // or not writing on change, then ignore the change
    if( updateInProgress == true || !writeOnChange )
    {
        return;
    }

    // Get the variable to write to
    QEFloating* qca = (QEFloating*)getQcaItem(0);

    /* If a QCa object is present (if there is a variable to write to)
     * then write the value
     */
    if( qca )
    {
        // Attempt to write the data if the destination data type is known.
        // It is not known until a connection is established.
        if( qca->dataTypeKnown() )
        {
            currentValue = (value/scale)+offset;
            qca->writeFloating( currentValue );
        }
        else
        {
            // Inform the user that the write could not be performed.
            // It is normally not possible to get here. If the connection or link has not
            // yet been established (and therefore the data type is unknown) then the user
            // interface object should be unaccessable. This code is here in the event that
            // the user can, by design or omision, still attempt a write.
            sendMessage( "Could not write value as type is not known yet.", "QESlider::userValueChanged()",
                          message_types ( MESSAGE_TYPE_WARNING ) );
        }
    }
}
コード例 #15
0
ファイル: QEPeriodic.cpp プロジェクト: rorydog1/epics
/*
    Button click event.
    Present the element selection dialog.

    Note, this function may be called if no PVs were defined since this widget can also be used just to signal an element selection
*/
void QEPeriodic::userClicked() {

    // Get the variables to write to
    // The write button uses the first two variables
    QEFloating *qca1 = (QEFloating*)getQcaItem(0);
    QEFloating *qca2 = (QEFloating*)getQcaItem(1);

    // Build a list of what buttons should be enabled
    // !! This could be build once during construction, or when userInfo enabled is changed??
    QList<bool> enabledList;
    QList<QString> elementList;
    for( int i = 0; i < NUM_ELEMENTS; i++ )
    {
        elementList.append( elementInfo[i].symbol );
        enabledList.append( userInfo[i].enable );
    }

    // Present the element selection dialog
    PeriodicDialog dialog( writeButton );

    // The dialog object constructed post QEPeriodic construction -apply scaling.
    QEScaling::applyToWidget ( &dialog );

    dialog.setElement( writeButton->text(), enabledList, elementList );
    dialog.exec( writeButton );

    // Use the selected element
    QString symbol = dialog.getElement();
    if( symbol.size() )
    {
        writeButton->setText( symbol );

        // Value selected from element info or user info depending on type
        double value;

        for( int i = 0; i < NUM_ELEMENTS; i++ )
        {
            if( elementInfo[i].symbol.compare( symbol ) == 0 )
            {
                // Write the user values to the variables if present
                if( qca1 )
                {
                    switch( variableType1 )
                    {
                    case VARIABLE_TYPE_NUMBER:            value = elementInfo[i].number;           break;
                    case VARIABLE_TYPE_ATOMIC_WEIGHT:     value = elementInfo[i].atomicWeight;     break;
                    case VARIABLE_TYPE_MELTING_POINT:     value = elementInfo[i].meltingPoint;     break;
                    case VARIABLE_TYPE_BOILING_POINT:     value = elementInfo[i].boilingPoint;     break;
                    case VARIABLE_TYPE_DENSITY:           value = elementInfo[i].density;          break;
                    case VARIABLE_TYPE_GROUP:             value = elementInfo[i].group;            break;
                    case VARIABLE_TYPE_IONIZATION_ENERGY: value = elementInfo[i].ionizationEnergy; break;
                    case VARIABLE_TYPE_USER_VALUE_1:      value = userInfo[i].value1;              break;
                    case VARIABLE_TYPE_USER_VALUE_2:      value = userInfo[i].value2;              break;
                    }
                    qca1->writeFloating( value );
                }
                if( qca2 )
                {
                    switch( variableType2 )
                    {
                    case VARIABLE_TYPE_NUMBER:            value = elementInfo[i].number;           break;
                    case VARIABLE_TYPE_ATOMIC_WEIGHT:     value = elementInfo[i].atomicWeight;     break;
                    case VARIABLE_TYPE_MELTING_POINT:     value = elementInfo[i].meltingPoint;     break;
                    case VARIABLE_TYPE_BOILING_POINT:     value = elementInfo[i].boilingPoint;     break;
                    case VARIABLE_TYPE_DENSITY:           value = elementInfo[i].density;          break;
                    case VARIABLE_TYPE_GROUP:             value = elementInfo[i].group;            break;
                    case VARIABLE_TYPE_IONIZATION_ENERGY: value = elementInfo[i].ionizationEnergy; break;
                    case VARIABLE_TYPE_USER_VALUE_1:      value = userInfo[i].value1;              break;
                    case VARIABLE_TYPE_USER_VALUE_2:      value = userInfo[i].value2;              break;
                    }
                    qca2->writeFloating( value );
                }

                // Emit a signal indicating the user has selected an element
                emit userElementChanged( symbol );
                selectedSymbol = symbol;

                break;
            }
        }
    }
}
コード例 #16
0
ファイル: QEPeriodic.cpp プロジェクト: rorydog1/epics
// Determine the element text required for the component (either the write button or the readback label)
// Multiple elements may match the same values (for example, where a compound
// is positioned on a reference foil stage). To avoid matching another element to the one
// selected (because the other element has the same values) The current write button element is
// checked for a match first. If it is even an approximate match it is selected. If it does not match,
// then the closest element match is returned.
bool QEPeriodic::getElementTextForValue( const double& value, const unsigned int& variableIndex, QEPeriodicComponentData& componentData, const QString& currentText, QString& newText )
{
    // Save the value
    if( variableIndex == componentData.variableIndex1 )
    {
        componentData.lastData1 = value;
        componentData.haveLastData1 = true;
    }
    else if( variableIndex == componentData.variableIndex2 )
    {
        componentData.lastData2 = value;
        componentData.haveLastData2 = true;
    }

    // Get the related QCa data objects.
    // We won't be using them for much - their presence (or absense) just tells us what data to expect.
    QEString* qca1 = (QEString*)getQcaItem(componentData.variableIndex1);
    QEString* qca2 = (QEString*)getQcaItem(componentData.variableIndex2);

    // If all required data is available...
    if( ( qca1 && componentData.haveLastData1 && qca2 && componentData.haveLastData2 ) ||   // If both inputs are required and are present
        ( qca1 && componentData.haveLastData1 && !qca2 ) ||                   // Or if only first is required and is present
        ( !qca1 && qca2 && componentData.haveLastData2 ) )                    // Or if only second is required and is present
    {
        // ... update the element

        int i;
        float match = 0.0;  // 0.0 = no match through to 1.0 = perfect match

        // Look for the index of the currently selected element
        for( i = 0; i < NUM_ELEMENTS; i++ )
        {
            if( elementInfo[i].symbol.compare( currentText ) == 0 )
                break;
        }

        // If there is a currently selected element, check if it matches the current values first
        if( i != NUM_ELEMENTS )
        {
            match =  elementMatch( i, qca1!=NULL, componentData.lastData1, qca2!=NULL, componentData.lastData2 );
        }

        // If there was no currently selected element, or it didn't match the current values,
        // check each element looking for one that matches the current values best
        if( match == 0.0 )
        {
            float bestMatch = 0.0;
            int bestElement = 0;

            for( i = 0; i < NUM_ELEMENTS; i++ )
            {
                match =  elementMatch( i, qca1!=NULL, componentData.lastData1, qca2!=NULL, componentData.lastData2 );
                if( match > bestMatch )
                {
                    bestMatch = match;
                    bestElement = i;
                }
            }
            match = bestMatch;
            i = bestElement;
        }

        // If an element matched, display it and emit any related text
        // Note, 'i' is valid if a match has been found
        if( match > 0.0 )
        {
            newText = elementInfo[i].symbol;
            emit dbElementChanged( userInfo[i].elementText );
        }

        // If no element matched, display a neutral string and it emit an empty string
        else
        {
            newText = "--";
            emit dbElementChanged( "" );
        }
        return true;
    }

    // Don't have all data required to set a value yet
    else
    {
        return false;
    }

}
コード例 #17
0
// useDbPrecision
// Note, for most widgets with an 'useDbPrecision' property, the property is passed to a
//       QEStringFormatting class where it is used to determine the precision when formatting numbers as a string.
//       In this case, it is used to determine the spin box number-of-decimals property.
void QESpinBox::setUseDbPrecisionForDecimals( bool useDbPrecisionForDecimalIn )
{
    useDbPrecisionForDecimal = useDbPrecisionForDecimalIn;
    qcaobject::QCaObject* qca = (QEFloating*)getQcaItem(0);
    setDecimalsFromPrecision( qca );
}
コード例 #18
0
void QESpinBox::setAddUnitsAsSuffix( bool addUnitsAsSuffixIn )
{
    addUnitsAsSuffix = addUnitsAsSuffixIn;
    qcaobject::QCaObject* qca = (QEFloating*)getQcaItem(0);
    setSuffixEgu( qca );
}
コード例 #19
0
/*
    Button click event.
*/
void QEGenericButton::userClicked( bool checked )
{
    // Do nothing if nothing to do. (no point asking for confirmation or password)
    // Then keep doing nothing if user confirmation required but not given, or password required but not given
    if(( !writeOnClick && programLauncher.getProgram().isEmpty() && guiName.isEmpty() ) ||  !confirmAction() || !checkPassword() )
        return;

    // Get the variable to write to
    QEString *qca = (QEString*)getQcaItem(0);

    // If the object is set up to write when the user clicks the button
    // emit a signal
    // Also, if a QCa object is present (if there is a variable to write to)
    // then write the value
    if( writeOnClick )
    {
        // Determine the string to write
        QString writeText;
        if( !checked )
        {
            writeText = clickText;
        }
        else
        {
            writeText = clickCheckedText;
        }

        writeText = substituteThis( writeText );

        // Emit a 'clicked' signal
        emitClicked( writeText.toInt() );

        // Write to the variable if present
        if( qca )
        {
            QString error;
            if( !qca->writeString( writeText, error ) )
            {
                QMessageBox::warning( (QWidget*)getButtonQObject(), QString( "Write failed" ), error, QMessageBox::Cancel );
            }
        }
    }

    // If there is a command to run, run it, with substitutions applied to the command and arguments
    programLauncher.launch( (VariableNameManager*)this, getButtonQObject() );

    // If a new GUI is required, start it
    if( !guiName.isEmpty() )
    {

        // Publish the profile this button recieved
        publishOwnProfile();

        // Extend any variable name substitutions with this button's substitutions
        // Like most other macro substitutions, the substitutions already present take precedence.
        addMacroSubstitutions( getVariableNameSubstitutions() );

        // Extend any variable name substitutions with this button's priority substitutions
        // Unlike most other macro substitutions, these macro substitutions take precedence over
        // substitutions already present.
        addPriorityMacroSubstitutions( prioritySubstitutions );

        // Start the GUI
        emitNewGui( QEActionRequests( substituteThis( guiName ), customisationName, creationOption ) );

        // Remove this button's priority macro substitutions now all its children are created
        removePriorityMacroSubstitutions();

        // Remove this button's normal macro substitutions now all its children are created
        removeMacroSubstitutions();

        // Release the profile now all QE widgets have been created
        releaseProfile();
    }
}
コード例 #20
0
ファイル: QEGenericEdit.cpp プロジェクト: rorydog1/epics
//------------------------------------------------------------------------------
// The user has 'finished editing' such as pressed return/enter or moved
// focus from the object.
// Note, it doesn't matter if the user presses return and both this function
// AND userReturnPressed() is called since setText is called in each to clear
// the 'isModified' flag. So, the first called will perform the write, the
// second (if any) will do nothing.
//
void QEGenericEdit::userEditingFinished()
{
    // If not connected, do nothing
    if( !isConnected )
    {
        return;
    }

    // Do nothing if the user is still effectivly working with the widget (just moved to a dialog box)
    // Any signals received while messageDialogPresent is true should be ignored.
    // A signal occurs after the 'write failed' dialog closes, so a it sets
    // writeFailMessageDialogPresent to allow this code to ignore the signal.
    if( messageDialogPresent || writeFailMessageDialogPresent )
    {
        if( !messageDialogPresent )
        {
            writeFailMessageDialogPresent = false;
            setFocus();
        }
        return;
    }

    // If no changes were made by the user, do nothing
    if( !isModified() || !writeOnFinish )
    {
        return;
    }

    // Get the variable to write to
    qcaobject::QCaObject *qca = getQcaItem(0);

    // If a QCa object is present (if there is a variable to write to)
    // and the object is set up to write when the user changes focus away from the object
    // and the text has actually changed
    // then write the value
    if( qca && writeOnLoseFocus )
    {
       // Note: getValue is a dispatching hook procedure.
       writeValue( qca, getValue () );
    }

    // If, for what ever reason, the value has been changed by the user but not but not written
    // check with the user what to do about it.
    else
    {
        messageDialogPresent = true;
        int confirm = QMessageBox::warning( this, "Value changed", "You altered a value but didn't write it.\nDo you want to write this value?",
                                            QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::No );
        messageDialogPresent = false;

        switch( confirm )
        {
            // Write the value
            case QMessageBox::Yes:
                if( qca ) {
                   // Note: getValue is a dispatching hook procedure.
                   writeValue( qca, getValue () );
                }
                break;

            // Abort the write, revert to latest value
            case QMessageBox::No:
                setValue( lastValue );       // Note, also clears 'isModified' flag
                                             // setValue  is dispatching hook function
                break;

            // Don't write the value, move back to the field being edited
            case QMessageBox::Cancel:
                setFocus();
                break;
        }
    }
}