File indexing completed on 2024-04-14 04:15:17

0001 /*
0002     SPDX-FileCopyrightText: 2001 The Kompany
0003     SPDX-FileCopyrightText: 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
0004     SPDX-FileCopyrightText: 2002-2003 Marcus Meissner <marcus@jet.franken.de>
0005     SPDX-FileCopyrightText: 2003 Nadeem Hasan <nhasan@nadmm.com>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "kameraconfigdialog.h"
0011 
0012 #include <QCheckBox>
0013 #include <QComboBox>
0014 #include <QDialogButtonBox>
0015 #include <QFrame>
0016 #include <QGroupBox>
0017 #include <QLabel>
0018 #include <QLineEdit>
0019 #include <QPushButton>
0020 #include <QRadioButton>
0021 #include <QScrollArea>
0022 #include <QSlider>
0023 #include <QVBoxLayout>
0024 
0025 #include <KLocalizedString>
0026 
0027 #include "kcm_kamera_log.h"
0028 
0029 KameraConfigDialog::KameraConfigDialog(Camera * /*camera*/, CameraWidget *widget, QWidget *parent)
0030     : QDialog(parent)
0031     , m_widgetRoot(widget)
0032 {
0033     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
0034 
0035     auto mainWidget = new QWidget(this);
0036     auto mainLayout = new QVBoxLayout;
0037     setLayout(mainLayout);
0038     mainLayout->addWidget(mainWidget);
0039     mainLayout->setContentsMargins(0, 0, 0, 0);
0040 
0041     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0042     okButton->setDefault(true);
0043     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0044 
0045     connect(buttonBox, &QDialogButtonBox::accepted, this, &KameraConfigDialog::accept);
0046     connect(buttonBox, &QDialogButtonBox::rejected, this, &KameraConfigDialog::reject);
0047     okButton->setDefault(true);
0048     setModal(true);
0049 
0050     auto main = new QFrame(this);
0051     mainLayout->addWidget(main);
0052 
0053     // Sets a layout for the frame, which is the parent of the GP_WIDGET_WINDOW
0054     auto topLayout = new QVBoxLayout(main);
0055     topLayout->setContentsMargins(0, 0, 0, 0);
0056 
0057     m_tabWidget = nullptr;
0058 
0059     appendWidget(main, widget);
0060 
0061     connect(okButton, &QPushButton::clicked, this, &KameraConfigDialog::slotOk);
0062     mainLayout->addWidget(buttonBox);
0063 }
0064 
0065 void KameraConfigDialog::appendWidget(QWidget *parent, CameraWidget *widget)
0066 {
0067     QWidget *newParent = parent;
0068 
0069     CameraWidgetType widget_type;
0070     const char *widget_name;
0071     const char *widget_info;
0072     const char *widget_label;
0073     float widget_value_float;
0074     int widget_value_int;
0075     const char *widget_value_string = nullptr;
0076     gp_widget_get_type(widget, &widget_type);
0077     gp_widget_get_label(widget, &widget_label);
0078     gp_widget_get_info(widget, &widget_info);
0079     gp_widget_get_name(widget, &widget_name);
0080 
0081     QString whats_this = QString::fromLocal8Bit(widget_info); // gphoto2 doesn't seem to have any standard for i18n
0082 
0083     // Add this widget to parent
0084     switch (widget_type) {
0085     case GP_WIDGET_WINDOW: {
0086         setWindowTitle(QString::fromLocal8Bit(widget_label));
0087         break;
0088     }
0089     case GP_WIDGET_SECTION: {
0090         if (!m_tabWidget) {
0091             m_tabWidget = new QTabWidget(parent);
0092             parent->layout()->addWidget(m_tabWidget);
0093         }
0094         auto tab = new QWidget;
0095         // widgets are to be aligned vertically in the tab
0096         auto tabLayout = new QVBoxLayout(tab);
0097         tabLayout->setContentsMargins(0, 0, 0, 0);
0098         m_tabWidget->addTab(tab, QString::fromLocal8Bit(widget_label));
0099 
0100         // Add scroll area
0101         auto scrollArea = new QScrollArea(tab);
0102         scrollArea->setWidgetResizable(true);
0103         scrollArea->setFrameShape(QFrame::NoFrame);
0104         tabLayout->addWidget(scrollArea);
0105 
0106         // Add a container widget to hold the page
0107         auto tabContainer = new QWidget(tab);
0108         // Add a layout for later parent->layout()->... calls
0109         new QVBoxLayout(tabContainer);
0110 
0111         // Set the container as the widget to be managed by the ScrollArea
0112         scrollArea->setWidget(tabContainer);
0113         scrollArea->show();
0114 
0115         newParent = tabContainer;
0116         break;
0117     }
0118     case GP_WIDGET_TEXT:
0119     case GP_WIDGET_RANGE:
0120     case GP_WIDGET_TOGGLE: {
0121         // Share the QGridLayout code
0122         auto grid = new QWidget(parent);
0123         auto gridLayout = new QGridLayout(grid);
0124         grid->setLayout(gridLayout);
0125         parent->layout()->addWidget(grid);
0126 
0127         QLabel *label = nullptr;
0128         if (widget_type == GP_WIDGET_TEXT) {
0129             gp_widget_get_value(widget, &widget_value_string);
0130 
0131             label = new QLabel(QString::fromLocal8Bit(widget_label) + QLatin1Char(':'), grid);
0132             auto lineEdit = new QLineEdit(widget_value_string, grid);
0133 
0134             gridLayout->addWidget(lineEdit, 0, 1, Qt::AlignRight);
0135             m_wmap.insert(widget, lineEdit);
0136         } else if (widget_type == GP_WIDGET_RANGE) {
0137             float widget_low;
0138             float widget_high;
0139             float widget_increment;
0140             gp_widget_get_range(widget, &widget_low, &widget_high, &widget_increment);
0141             gp_widget_get_value(widget, &widget_value_float);
0142 
0143             label = new QLabel(QString::fromLocal8Bit(widget_label) + ':', grid);
0144             auto slider = new QSlider(Qt::Horizontal, grid);
0145 
0146             gridLayout->addWidget(slider, 0, 1, Qt::AlignRight);
0147             m_wmap.insert(widget, slider);
0148         } else if (widget_type == GP_WIDGET_TOGGLE) {
0149             gp_widget_get_value(widget, &widget_value_int);
0150 
0151             label = new QLabel(QString::fromLocal8Bit(widget_label), grid);
0152             auto checkBox = new QCheckBox(grid);
0153             checkBox->setChecked(widget_value_int);
0154 
0155             gridLayout->addWidget(checkBox, 0, 1, Qt::AlignRight);
0156             m_wmap.insert(widget, checkBox);
0157             break;
0158         }
0159         if (label) {
0160             gridLayout->addWidget(label, 0, 0, Qt::AlignLeft);
0161         }
0162         break;
0163     }
0164     case GP_WIDGET_RADIO: {
0165         gp_widget_get_value(widget, &widget_value_string);
0166 
0167         int count = gp_widget_count_choices(widget);
0168         // KDE4 code used Q3V/HBoxGroup to specify alignment based on count
0169         // For fewer than 5 options, align them horizontally
0170         QBoxLayout *layout;
0171         if (count < 5) {
0172             layout = new QHBoxLayout;
0173         } else {
0174             layout = new QVBoxLayout;
0175         }
0176         auto buttonGroup = new QGroupBox(QString::fromLocal8Bit(widget_label), parent);
0177         parent->layout()->addWidget(buttonGroup);
0178 
0179         for (int i = 0; i < count; ++i) {
0180             const char *widget_choice;
0181             gp_widget_get_choice(widget, i, &widget_choice);
0182 
0183             auto newestButton = new QRadioButton(widget_choice);
0184             if (widget_value_string && !strcmp(widget_value_string, widget_choice)) {
0185                 newestButton->setChecked(true);
0186             }
0187             layout->addWidget(newestButton);
0188         }
0189         m_wmap.insert(widget, buttonGroup);
0190 
0191         buttonGroup->setLayout(layout);
0192 
0193         if (!whats_this.isEmpty()) {
0194             buttonGroup->setWhatsThis(whats_this);
0195         }
0196 
0197         break;
0198     }
0199     case GP_WIDGET_MENU: {
0200         gp_widget_get_value(widget, &widget_value_string);
0201 
0202         auto comboBox = new QComboBox(parent);
0203         parent->layout()->addWidget(comboBox);
0204         comboBox->clear();
0205         for (int i = 0; i < gp_widget_count_choices(widget); ++i) {
0206             const char *widget_choice;
0207             gp_widget_get_choice(widget, i, &widget_choice);
0208 
0209             comboBox->addItem(widget_choice);
0210             if (widget_value_string && !strcmp(widget_value_string, widget_choice))
0211                 comboBox->setCurrentIndex(i);
0212         }
0213         m_wmap.insert(widget, comboBox);
0214 
0215         if (!whats_this.isEmpty()) {
0216             comboBox->setWhatsThis(whats_this);
0217         }
0218 
0219         break;
0220     }
0221     case GP_WIDGET_BUTTON: {
0222         // TODO
0223         // I can't see a way of implementing this. Since there is
0224         // no way of telling which button sent you a signal, we
0225         // can't map to the appropriate widget->callback
0226         auto label = new QLabel(i18n("Button (not supported by KControl)"), parent);
0227         parent->layout()->addWidget(label);
0228 
0229         break;
0230     }
0231     case GP_WIDGET_DATE: {
0232         // TODO
0233         auto label = new QLabel(i18n("Date (not supported by KControl)"), parent);
0234         parent->layout()->addWidget(label);
0235 
0236         break;
0237     }
0238     default:
0239         return;
0240     }
0241 
0242     // Append all this widgets children
0243     for (int i = 0; i < gp_widget_count_children(widget); ++i) {
0244         CameraWidget *widget_child;
0245         gp_widget_get_child(widget, i, &widget_child);
0246         appendWidget(newParent, widget_child);
0247     }
0248 
0249     if (widget_type == GP_WIDGET_SECTION) {
0250         // Get latest tab
0251         QWidget *tab = m_tabWidget->widget(m_tabWidget->count() - 1);
0252         auto scrollArea = dynamic_cast<QScrollArea *>(tab->children().at(1));
0253         if (scrollArea) {
0254             auto vbox_layout = dynamic_cast<QVBoxLayout *>(scrollArea->widget()->layout());
0255             if (vbox_layout) {
0256                 vbox_layout->addStretch();
0257             }
0258         }
0259     }
0260 }
0261 
0262 void KameraConfigDialog::updateWidgetValue(CameraWidget *widget)
0263 {
0264     CameraWidgetType widget_type;
0265     gp_widget_get_type(widget, &widget_type);
0266 
0267     switch (widget_type) {
0268     case GP_WIDGET_WINDOW:
0269         // nothing to do
0270         break;
0271     case GP_WIDGET_SECTION:
0272         // nothing to do
0273         break;
0274     case GP_WIDGET_TEXT: {
0275         auto lineEdit = static_cast<QLineEdit *>(m_wmap[widget]);
0276         gp_widget_set_value(widget, (void *)lineEdit->text().toLocal8Bit().data());
0277 
0278         break;
0279     }
0280     case GP_WIDGET_RANGE: {
0281         auto slider = static_cast<QSlider *>(m_wmap[widget]);
0282         float value_float = slider->value();
0283         gp_widget_set_value(widget, (void *)&value_float);
0284 
0285         break;
0286     }
0287     case GP_WIDGET_TOGGLE: {
0288         auto checkBox = static_cast<QCheckBox *>(m_wmap[widget]);
0289         int value_int = checkBox->isChecked() ? 1 : 0;
0290         gp_widget_set_value(widget, (void *)&value_int);
0291 
0292         break;
0293     }
0294     case GP_WIDGET_RADIO: {
0295         auto buttonGroup = static_cast<QGroupBox *>(m_wmap[widget]);
0296         for (auto button : buttonGroup->children()) {
0297             auto radButton = static_cast<QRadioButton *>(button);
0298             if (radButton->isChecked()) {
0299                 gp_widget_set_value(widget, (void *)radButton->text().toLocal8Bit().data());
0300                 break;
0301             }
0302         }
0303         break;
0304     }
0305     case GP_WIDGET_MENU: {
0306         auto comboBox = static_cast<QComboBox *>(m_wmap[widget]);
0307         gp_widget_set_value(widget, (void *)comboBox->currentText().toLocal8Bit().data());
0308 
0309         break;
0310     }
0311     case GP_WIDGET_BUTTON:
0312         // nothing to do
0313         break;
0314     case GP_WIDGET_DATE: {
0315         // not implemented
0316         break;
0317     }
0318     }
0319 
0320     // Copy child widget values
0321     for (int i = 0; i < gp_widget_count_children(widget); ++i) {
0322         CameraWidget *widget_child;
0323         gp_widget_get_child(widget, i, &widget_child);
0324         updateWidgetValue(widget_child);
0325     }
0326 }
0327 
0328 void KameraConfigDialog::slotOk()
0329 {
0330     // Copy Qt widget values into CameraWidget hierarchy
0331     updateWidgetValue(m_widgetRoot);
0332 
0333     // 'ok' dialog
0334     accept();
0335 }
0336 
0337 #include "moc_kameraconfigdialog.cpp"