Thu, 12 Oct 2023 17:03:50 +0200
Changes in de iSpindel detail screen. Added a calibrate button and display the last update date and time.
/** * EditProduct.cpp is part of bmsapp. * * Tab 13, images and pictures. * * bmsapp is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * bmsapp is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ void EditProduct::images_Init() { qDebug() << "images_Init() count" << product->images_count << "current" << product->images_current << "size" << product->images_list.size(); // Start spinner /* * Clean old picture areas. */ if (product->images_count < 0 && product->images_list.size()) { qDebug() << " clean images_list"; ui->filmStrip->clear(); product->images_list.clear(); product->images_count = -1; product->images_current = -1; } /* * Load images data for this product uuid. */ if (product->images_count < 0) { QSqlQuery query; qDebug() << " loading data"; query.prepare("SELECT * FROM products_pics WHERE uuid=:uuid ORDER BY record"); query.bindValue(":uuid", product->uuid); query.exec(); if (query.lastError().isValid()) { qWarning() << "images_init()" << query.lastError(); QMessageBox::warning(this, tr("Database error"), tr("MySQL error: %1\n%2\n%3") .arg(query.lastError().nativeErrorCode()).arg(query.lastError().driverText()).arg(query.lastError().databaseText())); } product->images_count = 0; while (query.next()) { Images i; i.record = query.value("record").toInt(); i.uuid = query.value("uuid").toString(); i.pic_type = query.value("pic_type").toInt(); i.pic_data = query.value("pic_data").toByteArray(); i.pic_comment = query.value("pic_comment").toString(); i.filename = query.value("filename").toString(); i.timestamp = query.value("timestamp").toDateTime(); product->images_list.append(i); product->images_count++; } qDebug() << " loaded" << product->images_count << product->images_list.size(); if (product->images_count < 1) product->images_current = -1; else product->images_current = 0; } images_Thumbnails(); if (product->images_current >= 0) { ui->filmStrip->setCurrentRow(product->images_current); } images_Main(product->images_current); // Stop spinner } /* * Show thumbnails on the left. */ void EditProduct::images_Thumbnails() { qDebug() << "images_Thumbnails()" << product->images_list.size(); ui->filmStrip->clear(); for (int i = 0; i < product->images_list.size(); i++) { QListWidgetItem* newItem = new QListWidgetItem(); QString text = QCoreApplication::translate("PicType", g_prod_pic_types[product->images_list.at(i).pic_type]); newItem->setText(text); newItem->setBackground(QColor(0x45,0x53,0x64)); QPixmap outPixmap = QPixmap(); outPixmap.loadFromData(product->images_list.at(i).pic_data); // qDebug() << " " << outPixmap.width() << "x" << outPixmap.height() << "size" << outPixmap.size() << product->images_list.at(i).filename; // qDebug() << " " << ui->filmStrip->iconSize(); if (outPixmap.width() > 240 || outPixmap.height() > 180) newItem->setIcon(QIcon(outPixmap.scaled(240, 180, Qt::KeepAspectRatio, Qt::SmoothTransformation))); else newItem->setIcon(QIcon(outPixmap)); ui->filmStrip->addItem(newItem); } } void EditProduct::images_Main(int id) { qDebug() << " Main(" << id << ")"; ui->prevImage->setEnabled((product->images_count > 0 && product->images_current > 0) ? true:false); ui->nextImage->setEnabled((product->images_count > 0 && (product->images_current + 1) < product->images_count) ? true:false); ui->downloadImage->setEnabled((product->images_count > 0) ? true:false); ui->printImage->setEnabled((product->images_count > 0) ? true:false); ui->delImage->setEnabled((product->images_count > 0) ? true:false); const QSignalBlocker blocker1(ui->image_typeEdit); const QSignalBlocker blocker2(ui->image_commentEdit); if (product->images_count < 1) { ui->image_filenameEdit->setText(""); ui->image_timestampEdit->setText(""); ui->image_commentEdit->setText(""); ui->image_typeEdit->setCurrentIndex(0); ui->currentImage->clear(); return; } QPixmap outPixmap = QPixmap(); outPixmap.loadFromData(product->images_list.at(id).pic_data); // qDebug() << " " << outPixmap.width() << "x" << outPixmap.height() << "size" << outPixmap.size() << product->images_list.at(id).filename; if (outPixmap.width() > ui->currentImage->width() || outPixmap.height() > ui->currentImage->height()) ui->currentImage->setPixmap(outPixmap.scaled(ui->currentImage->width(), ui->currentImage->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); else ui->currentImage->setPixmap(outPixmap); ui->image_filenameEdit->setText(product->images_list.at(id).filename); ui->image_timestampEdit->setText(product->images_list.at(id).timestamp.toString(Qt::RFC2822Date)); ui->image_commentEdit->setText(product->images_list.at(id).pic_comment); ui->image_typeEdit->setCurrentIndex(product->images_list.at(id).pic_type); } void EditProduct::addImage_clicked() { QString fileName, dirName; QByteArray imageByteArray; QSqlQuery query; QSettings settings(QSettings::IniFormat, QSettings::UserScope, "mbse", "bmsapp"); /* * First check if the directory stored in the settings file exists. * It might be on a removable media that was last used ... * If so, fallback to the user's home directory. */ dirName = settings.value("paths/images").toString(); if (! QDir(dirName).exists()) { dirName = QDir::homePath(); } QFileDialog dialog1(this, tr("Open File")); dialog1.setDirectory(dirName); dialog1.setNameFilter("Images (*.bmp *.BMP *.gif *.GIF *.jpg *.JPG *.jpeg *.JPEG *.png *.PNG *.svg *.SVG)"); dialog1.setAcceptMode(QFileDialog::AcceptOpen); if (dialog1.exec() != QDialog::Accepted) return; /* * Save our current path */ settings.setValue("paths/images", dialog1.directory().absolutePath()); fileName = dialog1.selectedFiles().constFirst(); QImageReader reader(fileName); reader.setAutoTransform(true); const QImage newImage = reader.read(); if (newImage.isNull()) { QMessageBox::information(this, QGuiApplication::applicationDisplayName(), tr("Cannot load %1: %2") .arg(QDir::toNativeSeparators(fileName), reader.errorString())); return; } qDebug() << "Image" << fileName << newImage.width() << newImage.height() << "size" << newImage.sizeInBytes(); QBuffer buffer(&imageByteArray); buffer.open(QIODevice::WriteOnly); newImage.save(&buffer, "PNG"); /* Convert to lossless .png format. */ /* * Now that we have selected a valid image, create a new dialog so * we can add extra information for this image and a Save button. */ QDialog* dialog = new QDialog(this); dialog->resize(500, 490); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setObjectName(QString::fromUtf8("buttonBox")); buttonBox->setGeometry(QRect(10, 440, 480, 32)); buttonBox->setLayoutDirection(Qt::LeftToRight); buttonBox->setOrientation(Qt::Horizontal); buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Save); buttonBox->setCenterButtons(true); QLabel *imageLabel = new QLabel(dialog); imageLabel->setObjectName(QString::fromUtf8("imageLabel")); imageLabel->setGeometry(QRect(10, 10, 480, 320)); imageLabel->setAlignment(Qt::AlignCenter); imageLabel->setText(tr("Image here")); QPixmap outPixmap = QPixmap(); outPixmap.loadFromData(imageByteArray); if (outPixmap.width() > 480 || outPixmap.height() > 320) imageLabel->setPixmap(outPixmap.scaled(480, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation)); else imageLabel->setPixmap(outPixmap); QLabel *typeLabel = new QLabel(dialog); typeLabel->setObjectName(QString::fromUtf8("typeLabel")); typeLabel->setText(tr("Image type:")); typeLabel->setGeometry(QRect(10, 360, 141, 20)); typeLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QComboBox *typeEdit = new QComboBox(dialog); typeEdit->setObjectName(QString::fromUtf8("typeEdit")); typeEdit->setGeometry(QRect(160, 360, 161, 23)); for (int i = 0; i < 7; i++) typeEdit->addItem(QCoreApplication::translate("PicType", g_prod_pic_types[i])); typeEdit->setCurrentIndex(0); QLabel *commentLabel = new QLabel(dialog); commentLabel->setObjectName(QString::fromUtf8("commentLabel")); commentLabel->setText(tr("Image comment:")); commentLabel->setGeometry(QRect(10, 390, 141, 20)); commentLabel->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); QLineEdit *commentEdit = new QLineEdit(dialog); commentEdit->setObjectName(QString::fromUtf8("commentEdit")); commentEdit->setGeometry(QRect(160, 390, 320, 23)); commentEdit->setToolTip(tr("The comment for this image.")); connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); dialog->setModal(true); dialog->exec(); if (dialog->result() == QDialog::Rejected) { return; } disconnect(buttonBox, nullptr, nullptr, nullptr); QFileInfo fi(fileName); query.prepare("INSERT INTO products_pics SET uuid=:uuid, pic_type=:pic_type, pic_data=:pic_data, " "pic_comment=:pic_comment, filename=:filename, timestamp=:timestamp"); query.bindValue(":uuid", product->uuid); query.bindValue(":pic_type", typeEdit->currentIndex()); query.bindValue(":pic_data", imageByteArray); query.bindValue(":pic_comment", commentEdit->text()); query.bindValue(":filename", fi.completeBaseName() + ".png"); /* The image is converted to .png */ query.bindValue(":timestamp", fi.lastModified()); query.exec(); if (query.lastError().isValid()) { qWarning() << "addImage_clicked()" << query.lastError(); QMessageBox::warning(this, tr("Database error"), tr("MySQL error: %1\n%2\n%3") .arg(query.lastError().nativeErrorCode()).arg(query.lastError().driverText()).arg(query.lastError().databaseText())); } else { qDebug() << "new image Saved"; product->images_count = -1; // Force reload data images_Init(); } } void EditProduct::delImage_clicked() { qDebug() << "delImage_clicked()" << ui->filmStrip->currentRow(); int rc = QMessageBox::warning(this, tr("Delete image"), tr("Delete %1").arg(product->images_list.at(ui->filmStrip->currentRow()).filename), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (rc == QMessageBox::No) return; qDebug() << " delete record" << product->images_list.at(ui->filmStrip->currentRow()).record; QSqlQuery query; query.prepare("DELETE FROM products_pics WHERE record=:record"); query.bindValue(":record", product->images_list.at(ui->filmStrip->currentRow()).record); query.exec(); if (query.lastError().isValid()) { qWarning() << "delImage_clicked()" << query.lastError(); QMessageBox::warning(this, tr("Database error"), tr("MySQL error: %1\n%2\n%3") .arg(query.lastError().nativeErrorCode()).arg(query.lastError().driverText()).arg(query.lastError().databaseText())); } qDebug() << " delete record done"; product->images_count = -1; // Force reload data images_Init(); } void EditProduct::nextImage_clicked() { qDebug() << "nextImage_clicked()" << product->images_current << ui->filmStrip->currentRow(); if (product->images_count >= 0) { if ((product->images_current + 1) < product->images_count) { product->images_current++; ui->filmStrip->setCurrentRow(product->images_current); images_Main(product->images_current); } } } void EditProduct::prevImage_clicked() { qDebug() << "prevImage_clicked()" << product->images_current << ui->filmStrip->currentRow(); if (product->images_count >= 0) { if (product->images_current > 0) { product->images_current--; ui->filmStrip->setCurrentRow(product->images_current); images_Main(product->images_current); } } } void EditProduct::downloadImage_clicked() { QSettings settings(QSettings::IniFormat, QSettings::UserScope, "mbse", "bmsapp"); QString dirName; /* * First check if the directory stored in the settings file exists. * It might be on a removable media that was last used ... * If so, fallback to the user's home directory. */ dirName = settings.value("paths/download").toString(); if (! QDir(dirName).exists()) { dirName = QDir::homePath(); } QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), dirName + "/" + product->images_list.at(ui->filmStrip->currentRow()).filename, tr("Files (*.png)")); if (fileName == 0) { QMessageBox::warning(this, tr("Save File"), tr("No PNG file selected.")); return; } /* * Update to current selected path */ settings.setValue("paths/download", QFileInfo(fileName).absolutePath()); qDebug() << "downloadImage_clicked()" << ui->filmStrip->currentRow() << fileName; QFile file(fileName); file.open(QIODevice::WriteOnly); file.write(product->images_list.at(ui->filmStrip->currentRow()).pic_data); if (!file.setFileTime(product->images_list.at(ui->filmStrip->currentRow()).timestamp, QFileDevice::FileModificationTime)) { qWarning() << "Failed to modify modify time!"; } if (!file.setFileTime(product->images_list.at(ui->filmStrip->currentRow()).timestamp, QFileDevice::FileAccessTime)) { qWarning() << "Failed to modify access time!"; } file.close(); QMessageBox::information(this, tr("Save File"), tr("Saved %1").arg(product->images_list.at(ui->filmStrip->currentRow()).filename)); } void EditProduct::printImage_clicked() { qDebug() << "printImage_clicked()" << product->images_current << ui->filmStrip->currentRow(); } void EditProduct::selectImage_clicked(QListWidgetItem *val) { qDebug() << "selectImage_clicked()" << ui->filmStrip->currentRow(); if (product->images_count > 0) { product->images_current = ui->filmStrip->currentRow(); images_Main(product->images_current); } } void EditProduct::pictype_changed(int val) { if (product->images_count < 1) return; qDebug() << "pictype_changed" << val; product->images_list[ui->filmStrip->currentRow()].pic_type = val; QSqlQuery query; query.prepare("UPDATE products_pics SET pic_type=:pic_type WHERE record=:record"); query.bindValue(":pic_type", val); query.bindValue(":record", product->images_list.at(ui->filmStrip->currentRow()).record); query.exec(); if (query.lastError().isValid()) { qWarning() << "pictype_changed()" << query.lastError(); QMessageBox::warning(this, tr("Database error"), tr("MySQL error: %1\n%2\n%3") .arg(query.lastError().nativeErrorCode()).arg(query.lastError().driverText()).arg(query.lastError().databaseText())); } images_Thumbnails(); } void EditProduct::piccomment_changed() { if (product->images_count < 1) return; qDebug() << "piccomment_changed" << ui->image_commentEdit->text(); product->images_list[ui->filmStrip->currentRow()].pic_comment = ui->image_commentEdit->text(); QSqlQuery query; query.prepare("UPDATE products_pics SET pic_comment=:pic_comment WHERE record=:record"); query.bindValue(":pic_comment", ui->image_commentEdit->text()); query.bindValue(":record", product->images_list.at(ui->filmStrip->currentRow()).record); query.exec(); if (query.lastError().isValid()) { qWarning() << "pictype_changed()" << query.lastError(); QMessageBox::warning(this, tr("Database error"), tr("MySQL error: %1\n%2\n%3") .arg(query.lastError().nativeErrorCode()).arg(query.lastError().driverText()).arg(query.lastError().databaseText())); } }