File indexing completed on 2024-04-21 13:20:20

0001 /***************************************************************************
0002  *   Copyright (C) 2003-2005 by David Saxton                               *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "microsettingsdlg.h"
0012 #include "inputdialog.h"
0013 #include "microinfo.h"
0014 #include "micropackage.h"
0015 #include "microsettings.h"
0016 #include "pinmapping.h"
0017 #include "ui_microsettingswidget.h"
0018 
0019 #include <KComboBox>
0020 #include <KLineEdit>
0021 #include <KLocalizedString>
0022 #include <KMessageBox>
0023 
0024 #include <QDialogButtonBox>
0025 #include <QGroupBox>
0026 #include <QLabel>
0027 #include <QPushButton>
0028 #include <QRegExp>
0029 #include <QVBoxLayout>
0030 // #include <q3table.h>
0031 
0032 #include <ui_newpinmappingwidget.h>
0033 #include <ktechlab_debug.h>
0034 
0035 class MicroSettingsWidget : public QWidget, public Ui::MicroSettingsWidget
0036 {
0037 public:
0038     MicroSettingsWidget(QWidget *parent)
0039         : QWidget(parent)
0040     {
0041         setupUi(this);
0042     }
0043 };
0044 
0045 class NewPinMappingWidget : public QWidget, public Ui::NewPinMappingWidget
0046 {
0047 public:
0048     NewPinMappingWidget(QWidget *parent)
0049         : QWidget(parent)
0050     {
0051         setupUi(this);
0052     }
0053 };
0054 
0055 MicroSettingsDlg::MicroSettingsDlg(MicroSettings *microSettings, QWidget *parent)
0056     : QDialog(parent)
0057 {
0058     setModal(true);
0059     setWindowTitle(i18n("PIC Settings"));
0060 
0061     QVBoxLayout *mainLayout = new QVBoxLayout;
0062     setLayout(mainLayout);
0063 
0064     m_pMicroSettings = microSettings;
0065     m_pNewPinMappingWidget = nullptr;
0066     m_pNewPinMappingDlg = nullptr;
0067     m_pNewPinMappingOkButton = nullptr;
0068     m_pWidget = new MicroSettingsWidget(this);
0069 
0070     setWhatsThis(i18n("This dialog allows editing of the initial properties of the PIC"));
0071     m_pWidget->portsGroupBox->setWhatsThis(
0072         i18n("Edit the initial value of the ports here. For each binary number, the order from right-to-left is pins 0 through 7.<br><br>The \"Type (TRIS)\" edit shows the initial input/output state of the ports; 1 represents an input, "
0073              "and 0 an output.<br><br>The \"State (PORT)\" edit shows the initial high/low state of the ports; 1 represents a high, and 0 a low."));
0074     m_pWidget->variables->setWhatsThis(
0075         i18n("Edit the initial value of the variables here.<br><br>Note that the value of the variable can only be in the range 0->255. These variables will be initialized before any other code is executed."));
0076 
0077     // BEGIN Initialize initial port settings
0078     m_portNames = microSettings->microInfo()->package()->portNames();
0079 
0080     m_portTypeEdit.resize(m_portNames.size() /*, 0  - 2018.06.02 - initialized below */);
0081     m_portStateEdit.resize(m_portNames.size() /*, 0 - 2018.06.02 - initialized below */);
0082 
0083     uint row = 0;
0084     QStringList::iterator end = m_portNames.end();
0085     for (QStringList::iterator it = m_portNames.begin(); it != end; ++it, ++row) {
0086         // BEGIN Get current Type / State text
0087         QString portType = QString::number(microSettings->portType(*it), 2);
0088         QString portState = QString::number(microSettings->portState(*it), 2);
0089 
0090         QString fill;
0091         fill.fill('0', 8 - portType.length());
0092         portType.prepend(fill);
0093         fill.fill('0', 8 - portState.length());
0094         portState.prepend(fill);
0095         // END Get current Type / State text
0096 
0097         QGroupBox *groupBox = new QGroupBox(*it, m_pWidget->portsGroupBox);
0098 
0099         // groupBox->setColumnLayout(0, Qt::Vertical ); // 2018.06.02 - not needed
0100         groupBox->setLayout(new QVBoxLayout);
0101         groupBox->layout()->setSpacing(6);
0102         groupBox->layout()->setMargin(11);
0103         QGridLayout *groupBoxLayout = new QGridLayout(groupBox /*groupBox->layout() */);
0104         groupBoxLayout->setAlignment(Qt::AlignTop);
0105         groupBoxLayout->setSpacing(groupBox->layout()->spacing());
0106         groupBox->layout()->addItem(groupBoxLayout);
0107 
0108         // TODO: replace this with i18n( "the type", "Type (TRIS register):" );
0109         groupBoxLayout->addWidget(new QLabel(i18n("Type (TRIS register):"), groupBox), 0, 0);
0110         groupBoxLayout->addWidget(new QLabel(i18n("State (PORT register):"), groupBox), 1, 0);
0111 
0112         m_portTypeEdit[row] = new KLineEdit(portType, groupBox);
0113         groupBoxLayout->addWidget(m_portTypeEdit[row], 0, 1);
0114 
0115         m_portStateEdit[row] = new KLineEdit(portState, groupBox);
0116         groupBoxLayout->addWidget(m_portStateEdit[row], 1, 1);
0117 
0118         //      (dynamic_cast<QVBoxLayout*>(m_pWidget->portsGroupBox->layout()))->insertWidget( row, groupBox );
0119         (dynamic_cast<QVBoxLayout *>(m_pWidget->portsGroupBox->layout()))->addWidget(groupBox);
0120     }
0121     // END Initialize initial port settings
0122 
0123     // BEGIN Initialize initial variable settings
0124     // Hide row headers
0125     // m_pWidget->variables->setLeftMargin(0); // 2018.06.02 - fixed in UI file
0126 
0127     // Make columns as thin as possible
0128     // m_pWidget->variables->setColumnStretchable( 0, true );  // 2018.06.02 - to be fixed
0129     // m_pWidget->variables->setColumnStretchable( 1, true );  // 2018.06.02 - to be fixed
0130     {
0131         QStringList headerLabels;
0132         headerLabels.append(i18n("Variable name"));
0133         headerLabels.append(i18n("Variable value"));
0134         m_pWidget->variables->setHorizontalHeaderLabels(headerLabels);
0135     }
0136 
0137     QStringList variableNames = microSettings->variableNames();
0138     row = 0;
0139     end = variableNames.end();
0140     for (QStringList::iterator it = variableNames.begin(); it != end; ++it) {
0141         VariableInfo *info = microSettings->variableInfo(*it);
0142         if (info) {
0143             qCDebug(KTL_LOG) << "add var: " << *it << " val: " << info->valueAsString();
0144             m_pWidget->variables->insertRow(row);
0145             QTableWidgetItem *varNameItem = new QTableWidgetItem(*it);
0146             m_pWidget->variables->setItem(row, 0, varNameItem);
0147             QTableWidgetItem *varValItem = new QTableWidgetItem(info->valueAsString());
0148             m_pWidget->variables->setItem(row, 1, varValItem);
0149             ++row;
0150         }
0151     }
0152     m_pWidget->variables->insertRow(row);
0153     qCDebug(KTL_LOG) << "row count: " << m_pWidget->variables->rowCount();
0154 
0155     connect(m_pWidget->variables, &QTableWidget::cellChanged, this, &MicroSettingsDlg::checkAddVariableRow);
0156     // END Initialize initial variable settings
0157 
0158     // BEGIN Initialize pin maps
0159     connect(m_pWidget->pinMapAdd, &QPushButton::clicked, this, &MicroSettingsDlg::slotCreatePinMap);
0160     connect(m_pWidget->pinMapModify, &QPushButton::clicked, this, &MicroSettingsDlg::slotModifyPinMap);
0161     connect(m_pWidget->pinMapRename, &QPushButton::clicked, this, &MicroSettingsDlg::slotRenamePinMap);
0162     connect(m_pWidget->pinMapRemove, &QPushButton::clicked, this, &MicroSettingsDlg::slotRemovePinMap);
0163 
0164     m_pinMappings = microSettings->pinMappings();
0165     m_pWidget->pinMapCombo->insertItems(m_pWidget->pinMapCombo->count(), m_pinMappings.keys());
0166 
0167     updatePinMapButtons();
0168     // END Initialize pin maps
0169 
0170     mainLayout->addWidget(m_pWidget);
0171 
0172     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Apply);
0173     mainLayout->addWidget(buttonBox);
0174     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0175     okButton->setDefault(true);
0176     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0177     connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0178     connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0179     connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &MicroSettingsDlg::slotApplyClicked);
0180 
0181     m_pWidget->adjustSize();
0182     adjustSize();
0183 }
0184 
0185 MicroSettingsDlg::~MicroSettingsDlg()
0186 {
0187 }
0188 
0189 void MicroSettingsDlg::accept()
0190 {
0191     slotSaveStuff();
0192     QDialog::accept();
0193     deleteLater();
0194 }
0195 
0196 void MicroSettingsDlg::slotApplyClicked()
0197 {
0198     slotSaveStuff();
0199     emit applyClicked();
0200 }
0201 
0202 void MicroSettingsDlg::slotSaveStuff()
0203 {
0204     for (int i = 0; i < m_portNames.size(); i++)
0205         savePort(i);
0206 
0207     m_pMicroSettings->removeAllVariables();
0208     for (int i = 0; i < m_pWidget->variables->rowCount(); i++)
0209         saveVariable(i);
0210 
0211     m_pMicroSettings->setPinMappings(m_pinMappings);
0212 }
0213 
0214 void MicroSettingsDlg::reject()
0215 {
0216     QDialog::reject();
0217     deleteLater();
0218 }
0219 
0220 QValidator::State MicroSettingsDlg::validatePinMapName(QString &name) const
0221 {
0222     name.replace(' ', '_');
0223 
0224     if (name.isEmpty())
0225         return QValidator::Intermediate;
0226 
0227     for (int i = 0; i < name.length(); ++i) {
0228         if (!name[i].isLetterOrNumber() && name[i] != '_')
0229             return QValidator::Invalid;
0230     }
0231 
0232     if (name[0].isNumber())
0233         return QValidator::Intermediate;
0234 
0235     if (m_pWidget->pinMapCombo->contains(name))
0236         return QValidator::Intermediate;
0237 
0238     return QValidator::Acceptable;
0239 }
0240 
0241 void MicroSettingsDlg::slotCheckNewPinMappingName(const QString &name)
0242 {
0243     // Validate name might change the name so that it is valid
0244     QString newName = name;
0245 
0246     if (m_pNewPinMappingOkButton) {
0247         m_pNewPinMappingOkButton->setEnabled(validatePinMapName(newName) == QValidator::Acceptable);
0248     }
0249 
0250     if (newName != name)
0251         m_pNewPinMappingWidget->nameEdit->setText(newName);
0252 }
0253 
0254 void MicroSettingsDlg::slotCreatePinMap()
0255 {
0256     m_pNewPinMappingDlg = new QDialog(this);
0257     m_pNewPinMappingDlg->setObjectName("New Pin Mapping Dlg");
0258     m_pNewPinMappingDlg->setModal(true);
0259     m_pNewPinMappingDlg->setWindowTitle(i18n("New Pin Mapping"));
0260     QVBoxLayout *mainLayout = new QVBoxLayout;
0261     m_pNewPinMappingDlg->setLayout(mainLayout);
0262     m_pNewPinMappingWidget = new NewPinMappingWidget(m_pNewPinMappingDlg);
0263     mainLayout->addWidget(m_pNewPinMappingWidget);
0264     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0265     m_pNewPinMappingOkButton = buttonBox->button(QDialogButtonBox::Ok);
0266     m_pNewPinMappingOkButton->setText(i18n("Create"));
0267     m_pNewPinMappingOkButton->setDefault(true);
0268     m_pNewPinMappingOkButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0269     connect(buttonBox, &QDialogButtonBox::accepted, m_pNewPinMappingDlg, &QDialog::accept);
0270     connect(buttonBox, &QDialogButtonBox::rejected, m_pNewPinMappingDlg, &QDialog::reject);
0271     mainLayout->addWidget(buttonBox);
0272 
0273     PinMappingNameValidator *validator = new PinMappingNameValidator(this);
0274     m_pNewPinMappingWidget->nameEdit->setValidator(validator);
0275 
0276     connect(m_pNewPinMappingWidget->nameEdit, &KLineEdit::textChanged, this, &MicroSettingsDlg::slotCheckNewPinMappingName);
0277     slotCheckNewPinMappingName(nullptr);
0278 
0279     int accepted = m_pNewPinMappingDlg->exec();
0280     unsigned selectedType = m_pNewPinMappingWidget->typeCombo->currentIndex();
0281     QString name = m_pNewPinMappingWidget->nameEdit->text();
0282 
0283     delete m_pNewPinMappingDlg;
0284     delete validator;
0285     m_pNewPinMappingDlg = nullptr;
0286     m_pNewPinMappingWidget = nullptr;
0287     m_pNewPinMappingOkButton = nullptr;
0288     if (accepted != QDialog::Accepted)
0289         return;
0290 
0291     PinMapping::Type type = PinMapping::Invalid;
0292 
0293     switch (selectedType) {
0294     case 0:
0295         type = PinMapping::SevenSegment;
0296         break;
0297 
0298     case 1:
0299         type = PinMapping::Keypad_4x3;
0300         break;
0301 
0302     case 2:
0303         type = PinMapping::Keypad_4x4;
0304         break;
0305 
0306     default:
0307         qCCritical(KTL_LOG) << "Unknown selected type " << type;
0308         break;
0309     }
0310 
0311     m_pinMappings[name] = PinMapping(type);
0312     m_pWidget->pinMapCombo->insertItem(m_pWidget->pinMapCombo->count(), name);
0313     // m_pWidget->pinMapCombo->setCurrentItem( m_pWidget->pinMapCombo->count() - 1 );
0314     m_pWidget->pinMapCombo->setCurrentItem(name);
0315 
0316     updatePinMapButtons();
0317     slotModifyPinMap();
0318 }
0319 
0320 void MicroSettingsDlg::slotRenamePinMap()
0321 {
0322     KComboBox *combo = m_pWidget->pinMapCombo;
0323 
0324     QString oldName = combo->currentText();
0325     if (oldName.isEmpty())
0326         return;
0327 
0328     PinMappingNameValidator *validator = new PinMappingNameValidator(this, oldName);
0329 
0330     bool ok = false;
0331     QString newName = InputDialog::getText(i18n("New Pin Map Name"), i18n("Name"), oldName, &ok, this, /* 0, */ validator);
0332 
0333     delete validator;
0334 
0335     if (!ok)
0336         return;
0337 
0338     if (newName == oldName)
0339         return;
0340 
0341     m_pinMappings[newName] = m_pinMappings[oldName];
0342     m_pinMappings.remove(oldName);
0343 
0344     // combo->setCurrentText( newName ); // 2018.12.02
0345     combo->setItemText(combo->currentIndex(), newName);
0346 }
0347 
0348 void MicroSettingsDlg::slotModifyPinMap()
0349 {
0350     QString name = m_pWidget->pinMapCombo->currentText();
0351     PinMapping pinMapping = m_pinMappings[name];
0352 
0353     PinMapEditor *pinMapEditor = new PinMapEditor(&pinMapping, m_pMicroSettings->microInfo(), this);
0354     pinMapEditor->setObjectName("PinMapEditor");
0355     int accepted = pinMapEditor->exec();
0356 
0357     delete pinMapEditor;
0358 
0359     if (accepted != QDialog::Accepted)
0360         return;
0361 
0362     m_pinMappings[name] = pinMapping;
0363 }
0364 
0365 void MicroSettingsDlg::slotRemovePinMap()
0366 {
0367     KComboBox *combo = m_pWidget->pinMapCombo;
0368 
0369     QString pinMapID = combo->currentText();
0370     if (pinMapID.isEmpty())
0371         return;
0372 
0373     m_pinMappings.remove(pinMapID);
0374     combo->removeItem(combo->currentIndex());
0375 
0376     updatePinMapButtons();
0377 }
0378 
0379 void MicroSettingsDlg::updatePinMapButtons()
0380 {
0381     bool havePinMaps = (m_pWidget->pinMapCombo->count() != 0);
0382 
0383     m_pWidget->pinMapModify->setEnabled(havePinMaps);
0384     m_pWidget->pinMapRename->setEnabled(havePinMaps);
0385     m_pWidget->pinMapRemove->setEnabled(havePinMaps);
0386 }
0387 
0388 void MicroSettingsDlg::savePort(int row)
0389 {
0390     QString port = m_portNames[row];
0391 
0392     int type, state;
0393 
0394     QString typeText = m_portTypeEdit[row]->text();
0395     bool typeOk = true;
0396     if (typeText.startsWith("0x", Qt::CaseInsensitive))
0397         type = typeText.remove(0, 2).toInt(&typeOk, 16);
0398     else if (typeText.contains(QRegExp("[^01]")))
0399         type = typeText.toInt(&typeOk, 10);
0400     else
0401         type = typeText.toInt(&typeOk, 2);
0402 
0403     if (!typeOk) {
0404         //      KMessageBox::error( this, i18n("Unregnised Port Type: %1", typeText) );
0405         return;
0406     }
0407 
0408     QString stateText = m_portStateEdit[row]->text();
0409     bool stateOk = true;
0410     if (stateText.startsWith("0x", Qt::CaseInsensitive))
0411         state = stateText.remove(0, 2).toInt(&stateOk, 16);
0412     else if (stateText.contains(QRegExp("[^01]")))
0413         state = stateText.toInt(&stateOk, 10);
0414     else
0415         state = stateText.toInt(&stateOk, 2);
0416 
0417     if (!stateOk) {
0418         //      KMessageBox::error( this, i18n("Unregnised Port State: %1", stateText) );
0419         return;
0420     }
0421 
0422     m_pMicroSettings->setPortState(port, state);
0423     m_pMicroSettings->setPortType(port, type);
0424 }
0425 
0426 void MicroSettingsDlg::saveVariable(int row)
0427 {
0428     QTableWidgetItem *nameItem = m_pWidget->variables->item(row, 0);
0429     if (!nameItem) {
0430         return;
0431     }
0432     QString name = nameItem->text();
0433     if (name.isEmpty())
0434         return;
0435 
0436     QTableWidgetItem *valueItem = m_pWidget->variables->item(row, 1);
0437     QString valueText;
0438     if (valueItem) {
0439         valueText = valueItem->text();
0440     }
0441     int value;
0442     bool ok = true;
0443     if (valueText.startsWith("0x", Qt::CaseInsensitive))
0444         value = valueText.remove(0, 2).toInt(&ok, 16);
0445     else
0446         value = valueText.toInt(&ok, 10);
0447 
0448     if (!ok) {
0449         KMessageBox::error(this, i18n("Invalid variable value: %1", valueText));
0450         return;
0451     }
0452 
0453     qCDebug(KTL_LOG) << "save variable: " << name << " val: " << value;
0454 
0455     m_pMicroSettings->setVariable(name, value, true);
0456     VariableInfo *info = m_pMicroSettings->variableInfo(name);
0457     if (info && info->valueAsString().toInt() != value) {
0458         //      info->setValue(value);
0459         //      info->permanent = true;
0460         info->initAtStart = true;
0461     }
0462 }
0463 
0464 void MicroSettingsDlg::checkAddVariableRow()
0465 {
0466     int lastRow = m_pWidget->variables->rowCount() - 1;
0467     if (QTableWidgetItem *lastItem = m_pWidget->variables->item(lastRow, 0)) {
0468         if (!lastItem->text().isEmpty()) {
0469             m_pWidget->variables->insertRow(lastRow + 1);
0470         }
0471     }
0472 }
0473 
0474 #include "moc_microsettingsdlg.cpp"