/*! 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(); } }
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 ); } } }
// 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; } }
// 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() ); } }
/*! 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() ); } }
/*! 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 ); } } }
/*! 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; } } }
// 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 ); } } }
/* 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 ); }
/* 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 ) ); } }
//------------------------------------------------------------------------------ // 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 () ); } }
//------------------------------------------------------------------------------ // 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 () ); } }
/* 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; } }
/* 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 ) ); } } }
/* 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; } } } }
// 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; } }
// 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 ); }
void QESpinBox::setAddUnitsAsSuffix( bool addUnitsAsSuffixIn ) { addUnitsAsSuffix = addUnitsAsSuffixIn; qcaobject::QCaObject* qca = (QEFloating*)getQcaItem(0); setSuffixEgu( qca ); }
/* 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(); } }
//------------------------------------------------------------------------------ // 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; } } }