File indexing completed on 2024-05-12 04:41:12
0001 /* AtCore KDE Libary for 3D Printers 0002 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0003 SPDX-FileCopyrightText: 2019-2020 Chris Rizzitello <rizzitello@kde.org> 0004 */ 0005 0006 #include "profilemanager.h" 0007 #include "atcore_default_folders.h" 0008 #include "machineinfo.h" 0009 0010 #include <QButtonGroup> 0011 #include <QCheckBox> 0012 #include <QComboBox> 0013 #include <QCompleter> 0014 #include <QCoreApplication> 0015 #include <QDir> 0016 #include <QGroupBox> 0017 #include <QHBoxLayout> 0018 #include <QLabel> 0019 #include <QLineEdit> 0020 #include <QRadioButton> 0021 #include <QSpinBox> 0022 #include <QToolButton> 0023 0024 ProfileManager::ProfileManager(QWidget *parent) 0025 : QWidget(parent) 0026 { 0027 auto newLabel = new QLabel(tr("Profile:")); 0028 cbProfile = new QComboBox(); 0029 cbProfile->setEditable(true); 0030 cbProfile->addItems(MachineInfo::instance()->profileNames()); 0031 cbProfile->setCompleter(new QCompleter(MachineInfo::instance()->profileNames())); 0032 connect(MachineInfo::instance(), &MachineInfo::profilesChanged, this, [this] { 0033 int index = cbProfile->currentIndex(); 0034 cbProfile->clear(); 0035 cbProfile->completer()->deleteLater(); 0036 cbProfile->addItems(MachineInfo::instance()->profileNames()); 0037 cbProfile->setCompleter(new QCompleter(MachineInfo::instance()->profileNames())); 0038 cbProfile->setCurrentIndex(std::min<int>(index, cbProfile->count() - 1)); 0039 }); 0040 0041 connect(cbProfile, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this] { 0042 if (MachineInfo::instance()->profileNames().contains(cbProfile->currentText())) { 0043 loadProfile(cbProfile->currentText()); 0044 } 0045 }); 0046 0047 connect(cbProfile->lineEdit(), &QLineEdit::editingFinished, this, &ProfileManager::onCbProfileEditingFinished); 0048 0049 auto newHLayout = new QHBoxLayout(); 0050 newHLayout->addWidget(newLabel); 0051 newHLayout->addWidget(cbProfile, 75); 0052 0053 auto newButton = new QToolButton(); 0054 newButton->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"), style()->standardIcon(QStyle::SP_DialogDiscardButton))); 0055 newButton->setToolTip(tr("Delete Current Profile")); 0056 newButton->setIconSize(QSize(fontMetrics().height(), fontMetrics().height())); 0057 connect(newButton, &QToolButton::clicked, this, [this] { 0058 if (!cbProfile->currentText().isEmpty()) { 0059 MachineInfo::instance()->removeProfile(cbProfile->currentText()); 0060 } 0061 }); 0062 0063 auto mainLayout = new QVBoxLayout(); 0064 newHLayout->addWidget(newButton); 0065 mainLayout->addLayout(newHLayout); 0066 auto profileLayout = new QVBoxLayout(); 0067 auto boxLayout = new QVBoxLayout(); 0068 0069 newLabel = new QLabel(tr("Name")); 0070 lineName = new QLineEdit(); 0071 connect(lineName, &QLineEdit::editingFinished, this, [this] { 0072 QString itemName = lineName->text(); 0073 if (MachineInfo::instance()->storeKey(cbProfile->currentText(), MachineInfo::KEY::NAME, itemName)) { 0074 loadProfile(itemName); 0075 } 0076 }); 0077 newHLayout = new QHBoxLayout; 0078 newHLayout->addWidget(newLabel); 0079 newHLayout->addWidget(lineName); 0080 profileLayout->addLayout(newHLayout); 0081 0082 newLabel = new QLabel(tr("Printer Type:")); 0083 radioDelta = new QRadioButton(tr("Delta")); 0084 radioCartesian = new QRadioButton(tr("Cartesian")); 0085 radioCartesian->setChecked(true); 0086 connect(radioCartesian, &QRadioButton::toggled, this, &ProfileManager::onRadioCartesianToggled); 0087 0088 newHLayout = new QHBoxLayout; 0089 newHLayout->addWidget(newLabel); 0090 newHLayout->addWidget(radioCartesian); 0091 newHLayout->addWidget(radioDelta); 0092 boxLayout->addLayout(newHLayout); 0093 0094 lblX = new QLabel(tr("Maximum X")); 0095 sbMaxX = new QSpinBox(); 0096 sbMaxX->setMaximum(std::numeric_limits<int>::max()); 0097 sbMaxX->setSuffix(QStringLiteral("mm")); 0098 connect(sbMaxX, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int value) { MachineInfo::instance()->storeKey(cbProfile->currentText(), MachineInfo::KEY::XMAX, value); }); 0099 0100 newHLayout = new QHBoxLayout; 0101 newHLayout->addWidget(lblX); 0102 newHLayout->addWidget(sbMaxX); 0103 boxLayout->addLayout(newHLayout); 0104 0105 newLabel = new QLabel(tr("Maximum Y")); 0106 sbMaxY = new QSpinBox(); 0107 sbMaxY->setMaximum(std::numeric_limits<int>::max()); 0108 sbMaxY->setSuffix(QStringLiteral("mm")); 0109 connect(sbMaxY, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int value) { MachineInfo::instance()->storeKey(cbProfile->currentText(), MachineInfo::KEY::YMAX, value); }); 0110 0111 newHLayout = new QHBoxLayout; 0112 newHLayout->setContentsMargins(0, 0, 0, 0); 0113 newHLayout->addWidget(newLabel); 0114 newHLayout->addWidget(sbMaxY); 0115 axisY = new QWidget(this); 0116 axisY->setLayout(newHLayout); 0117 boxLayout->addWidget(axisY); 0118 0119 lblZ = new QLabel(tr("Maximum Z")); 0120 sbMaxZ = new QSpinBox(); 0121 sbMaxZ->setMaximum(std::numeric_limits<int>::max()); 0122 sbMaxZ->setSuffix(QStringLiteral("mm")); 0123 connect(sbMaxZ, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int value) { MachineInfo::instance()->storeKey(cbProfile->currentText(), MachineInfo::KEY::ZMAX, value); }); 0124 0125 newHLayout = new QHBoxLayout; 0126 newHLayout->addWidget(lblZ); 0127 newHLayout->addWidget(sbMaxZ); 0128 boxLayout->addLayout(newHLayout); 0129 0130 auto groupBox = new QGroupBox(tr("Mechanics")); 0131 groupBox->setLayout(boxLayout); 0132 profileLayout->addWidget(groupBox); 0133 0134 boxLayout = new QVBoxLayout; 0135 newLabel = new QLabel(tr("Bed Maximum")); 0136 sbMaxBedTemp = new QSpinBox(); 0137 sbMaxBedTemp->setMaximum(999); 0138 sbMaxBedTemp->setSuffix(QStringLiteral(" ºC")); 0139 connect(sbMaxBedTemp, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int value) { MachineInfo::instance()->storeKey(cbProfile->currentText(), MachineInfo::KEY::MAXBEDTEMP, value); }); 0140 0141 newHLayout = new QHBoxLayout; 0142 newHLayout->addWidget(newLabel); 0143 newHLayout->addWidget(sbMaxBedTemp); 0144 boxLayout->addLayout(newHLayout); 0145 0146 sbMaxExtTemp = new QSpinBox(); 0147 sbMaxExtTemp->setMaximum(999); 0148 newLabel = new QLabel(tr("Extruder Maximum")); 0149 sbMaxExtTemp->setSuffix(QStringLiteral(" ºC")); 0150 connect(sbMaxExtTemp, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int value) { MachineInfo::instance()->storeKey(cbProfile->currentText(), MachineInfo::KEY::MAXEXTTEMP, value); }); 0151 0152 newHLayout = new QHBoxLayout(); 0153 newHLayout->addWidget(newLabel); 0154 newHLayout->addWidget(sbMaxExtTemp); 0155 boxLayout->addLayout(newHLayout); 0156 0157 checkAutoTempReport = new QCheckBox(tr("Auto Temperature Report")); 0158 checkAutoTempReport->setLayoutDirection(Qt::RightToLeft); 0159 connect(checkAutoTempReport, &QCheckBox::toggled, this, [this](bool checked) { MachineInfo::instance()->storeKey(cbProfile->currentText(), MachineInfo::KEY::AUTOTEMPREPORT, checked); }); 0160 boxLayout->addWidget(checkAutoTempReport, 0, Qt::AlignRight); 0161 0162 groupBox = new QGroupBox(tr("Temperature")); 0163 groupBox->setLayout(boxLayout); 0164 profileLayout->addWidget(groupBox); 0165 0166 boxLayout = new QVBoxLayout(); 0167 cbBaud = new QComboBox(); 0168 cbBaud->addItems(BAUDS); 0169 cbBaud->setCurrentText(QStringLiteral("115200")); 0170 connect(cbBaud, &QComboBox::currentTextChanged, this, [this](const QString &newText) { MachineInfo::instance()->storeKey(cbProfile->currentText(), MachineInfo::KEY::BAUDRATE, newText); }); 0171 0172 newLabel = new QLabel(tr("Bit Rate")); 0173 newHLayout = new QHBoxLayout(); 0174 newHLayout->addWidget(newLabel); 0175 newHLayout->addWidget(cbBaud); 0176 boxLayout->addLayout(newHLayout); 0177 0178 newLabel = new QLabel(tr("Firmware")); 0179 cbFirmware = new QComboBox(); 0180 cbFirmware->addItem(QStringLiteral("Auto-Detect")); 0181 cbFirmware->addItems(detectFWPlugins()); 0182 connect(cbFirmware, &QComboBox::currentTextChanged, this, [this](const QString &newText) { MachineInfo::instance()->storeKey(cbProfile->currentText(), MachineInfo::KEY::FIRMWARE, newText); }); 0183 0184 newHLayout = new QHBoxLayout(); 0185 newHLayout->addWidget(newLabel); 0186 newHLayout->addWidget(cbFirmware); 0187 boxLayout->addLayout(newHLayout); 0188 0189 linePostPause = new QLineEdit(); 0190 connect(linePostPause, &QLineEdit::editingFinished, this, [this] { MachineInfo::instance()->storeKey(cbProfile->currentText(), MachineInfo::KEY::POSTPAUSE, linePostPause->text()); }); 0191 0192 newLabel = new QLabel(tr("PostPause")); 0193 newHLayout = new QHBoxLayout(); 0194 newHLayout->addWidget(newLabel); 0195 newHLayout->addWidget(linePostPause); 0196 boxLayout->addLayout(newHLayout); 0197 0198 groupBox = new QGroupBox(tr("Advanced")); 0199 groupBox->setLayout(boxLayout); 0200 profileLayout->addWidget(groupBox); 0201 groupBox = new QGroupBox(tr("Profile")); 0202 groupBox->setLayout(profileLayout); 0203 mainLayout->addWidget(groupBox); 0204 setLayout(mainLayout); 0205 loadProfile(cbProfile->currentText()); 0206 } 0207 0208 void ProfileManager::onCbProfileEditingFinished() 0209 { 0210 if (MachineInfo::instance()->profileNames().contains(cbProfile->currentText())) { 0211 loadProfile(cbProfile->currentText()); 0212 return; 0213 } 0214 QMap<MachineInfo::KEY, QVariant> newProfile = {{MachineInfo::KEY::NAME, cbProfile->currentText()}, 0215 {MachineInfo::KEY::FIRMWARE, cbFirmware->currentText()}, 0216 {MachineInfo::KEY::BAUDRATE, cbBaud->currentText()}, 0217 {MachineInfo::KEY::POSTPAUSE, linePostPause->text()}, 0218 {MachineInfo::KEY::ISCARTESIAN, radioCartesian->isChecked()}, 0219 {MachineInfo::KEY::XMAX, sbMaxX->value()}, 0220 {MachineInfo::KEY::YMAX, sbMaxY->value()}, 0221 {MachineInfo::KEY::ZMAX, sbMaxZ->value()}, 0222 {MachineInfo::KEY::AUTOTEMPREPORT, checkAutoTempReport->isChecked()}, 0223 {MachineInfo::KEY::MAXBEDTEMP, sbMaxBedTemp->value()}, 0224 {MachineInfo::KEY::MAXEXTTEMP, sbMaxExtTemp->value()}}; 0225 MachineInfo::instance()->storeProfile(newProfile); 0226 loadProfile(newProfile[MachineInfo::KEY::NAME].toString()); 0227 } 0228 0229 void ProfileManager::onRadioCartesianToggled(bool checked) 0230 { 0231 axisY->setVisible(checked); 0232 if (checked) { 0233 lblX->setText(tr("Maximum X")); 0234 lblZ->setText(tr("Maximum Z")); 0235 } else { 0236 lblX->setText(tr("Radius")); 0237 lblZ->setText(tr("Height")); 0238 } 0239 if (MachineInfo::instance()->profileNames().contains(cbProfile->currentText())) { 0240 MachineInfo::instance()->storeKey(cbProfile->currentText(), MachineInfo::KEY::ISCARTESIAN, checked); 0241 } 0242 } 0243 0244 void ProfileManager::loadProfile(const QString &profileName) 0245 { 0246 if (profileName.isEmpty()) { 0247 return; 0248 } 0249 blockSignals(true); 0250 lineName->setText(MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::NAME).toString()); 0251 radioCartesian->setChecked(MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::ISCARTESIAN).toBool()); 0252 radioDelta->setChecked(!MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::ISCARTESIAN).toBool()); 0253 sbMaxX->setValue(MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::XMAX).toInt()); 0254 sbMaxY->setValue(MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::YMAX).toInt()); 0255 sbMaxZ->setValue(MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::ZMAX).toInt()); 0256 checkAutoTempReport->setChecked(MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::AUTOTEMPREPORT).toBool()); 0257 sbMaxBedTemp->setValue(MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::MAXBEDTEMP).toInt()); 0258 sbMaxExtTemp->setValue(MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::MAXEXTTEMP).toInt()); 0259 cbFirmware->setCurrentText(MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::FIRMWARE).toString()); 0260 cbBaud->setCurrentText(MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::BAUDRATE).toString()); 0261 linePostPause->setText(MachineInfo::instance()->readKey(profileName, MachineInfo::KEY::POSTPAUSE).toString()); 0262 cbProfile->setCurrentText(profileName); 0263 cbProfile->setCurrentIndex(MachineInfo::instance()->profileNames().indexOf(profileName)); 0264 blockSignals(false); 0265 } 0266 0267 QStringList ProfileManager::detectFWPlugins() 0268 { 0269 QStringList firmwares; 0270 for (const QString &path : AtCoreDirectories::pluginDir) { 0271 const auto pluginList = QDir(path).entryList({AtCoreDirectories::pluginExtFilter}, QDir::Files); 0272 for (QString file : pluginList) { 0273 file = file.split(QStringLiteral(".")).at(0).toLower().simplified(); 0274 if (file.startsWith(QStringLiteral("lib"))) 0275 file = file.remove(QStringLiteral("lib")); 0276 firmwares.append(file); 0277 } 0278 if (!firmwares.isEmpty()) 0279 break; //Use first path with valid files 0280 } 0281 return firmwares; 0282 }