File indexing completed on 2024-05-12 04:38:19
0001 /* 0002 SPDX-FileCopyrightText: 2006 Adam Treat <treat@kde.org> 0003 SPDX-FileCopyrightText: 2007 Dukju Ahn <dukjuahn@gmail.com> 0004 SPDX-FileCopyrightText: 2008 Andreas Pakuat <apaku@gmx.de> 0005 SPDX-FileCopyrightText: 2017 Friedrich W. H. Kossebau <kossebau@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "environmentwidget.h" 0011 0012 #include <QDialog> 0013 #include <QDialogButtonBox> 0014 #include <QHeaderView> 0015 #include <QPushButton> 0016 #include <QSortFilterProxyModel> 0017 #include <QLineEdit> 0018 #include <QPlainTextEdit> 0019 #include <QVBoxLayout> 0020 #include <QHBoxLayout> 0021 #include <QValidator> 0022 0023 #include <util/scopeddialog.h> 0024 0025 #include <KLocalizedString> 0026 0027 #include "environmentprofilelistmodel.h" 0028 #include "environmentprofilemodel.h" 0029 #include "placeholderitemproxymodel.h" 0030 #include "debug.h" 0031 0032 using namespace KDevelop; 0033 0034 0035 class ProfileNameValidator : public QValidator 0036 { 0037 Q_OBJECT 0038 0039 public: 0040 explicit ProfileNameValidator(EnvironmentProfileListModel* environmentProfileListModel, QObject* parent = nullptr); 0041 QValidator::State validate(QString& input, int& pos) const override; 0042 0043 private: 0044 const EnvironmentProfileListModel* const m_environmentProfileListModel; 0045 }; 0046 0047 ProfileNameValidator::ProfileNameValidator(EnvironmentProfileListModel* environmentProfileListModel, 0048 QObject* parent) 0049 : QValidator(parent) 0050 , m_environmentProfileListModel(environmentProfileListModel) 0051 { 0052 } 0053 0054 QValidator::State ProfileNameValidator::validate(QString& input, int& pos) const 0055 { 0056 Q_UNUSED(pos); 0057 0058 if (input.isEmpty()) { 0059 return QValidator::Intermediate; 0060 } 0061 if (m_environmentProfileListModel->hasProfile(input)) { 0062 return QValidator::Intermediate; 0063 } 0064 return QValidator::Acceptable; 0065 } 0066 0067 EnvironmentWidget::EnvironmentWidget( QWidget *parent ) 0068 : QWidget(parent) 0069 , m_environmentProfileListModel(new EnvironmentProfileListModel(this)) 0070 , m_environmentProfileModel(new EnvironmentProfileModel(m_environmentProfileListModel, this)) 0071 , m_proxyModel(new QSortFilterProxyModel(this)) 0072 { 0073 // setup ui 0074 ui.setupUi( this ); 0075 0076 ui.profileSelect->setModel(m_environmentProfileListModel); 0077 m_proxyModel->setSourceModel(m_environmentProfileModel); 0078 0079 auto* topProxyModel = new PlaceholderItemProxyModel(this); 0080 topProxyModel->setSourceModel(m_proxyModel); 0081 topProxyModel->setColumnHint(0, i18nc("@info:placeholder", "Enter variable...")); 0082 connect(topProxyModel, &PlaceholderItemProxyModel::dataInserted, this, &EnvironmentWidget::onVariableInserted); 0083 0084 ui.variableTable->setModel( topProxyModel ); 0085 ui.variableTable->horizontalHeader()->setSectionResizeMode( 0, QHeaderView::ResizeToContents ); 0086 ui.variableTable->horizontalHeader()->setSectionResizeMode( 1, QHeaderView::Stretch ); 0087 ui.removeVariableButton->setShortcut(Qt::Key_Delete); 0088 0089 connect(ui.removeVariableButton, &QPushButton::clicked, 0090 this, &EnvironmentWidget::removeSelectedVariables); 0091 connect(ui.batchModeEditButton, &QPushButton::clicked, 0092 this, &EnvironmentWidget::batchModeEditButtonClicked); 0093 0094 connect(ui.cloneProfileButton, &QPushButton::clicked, this, &EnvironmentWidget::cloneSelectedProfile); 0095 connect(ui.addProfileButton, &QPushButton::clicked, this, &EnvironmentWidget::addProfile); 0096 connect(ui.removeProfileButton, &QPushButton::clicked, this, &EnvironmentWidget::removeSelectedProfile); 0097 connect(ui.setAsDefaultProfileButton, &QPushButton::clicked, this, &EnvironmentWidget::setSelectedProfileAsDefault); 0098 connect(ui.profileSelect, QOverload<int>::of(&KComboBox::currentIndexChanged), 0099 this, &EnvironmentWidget::onSelectedProfileChanged); 0100 0101 connect(m_environmentProfileListModel, &EnvironmentProfileListModel::defaultProfileChanged, 0102 this, &EnvironmentWidget::onDefaultProfileChanged); 0103 connect(m_environmentProfileListModel, &EnvironmentProfileListModel::rowsInserted, 0104 this, &EnvironmentWidget::changed); 0105 connect(m_environmentProfileListModel, &EnvironmentProfileListModel::rowsRemoved, 0106 this, &EnvironmentWidget::changed); 0107 connect(m_environmentProfileListModel, &EnvironmentProfileListModel::defaultProfileChanged, 0108 this, &EnvironmentWidget::changed); 0109 0110 connect(ui.variableTable->selectionModel(), &QItemSelectionModel::selectionChanged, 0111 this, &EnvironmentWidget::updateDeleteVariableButton); 0112 connect(m_environmentProfileModel, &EnvironmentProfileModel::rowsInserted, 0113 this, &EnvironmentWidget::updateDeleteVariableButton); 0114 connect(m_environmentProfileModel, &EnvironmentProfileModel::rowsRemoved, 0115 this, &EnvironmentWidget::updateDeleteVariableButton); 0116 connect(m_environmentProfileModel, &EnvironmentProfileModel::modelReset, 0117 this, &EnvironmentWidget::updateDeleteVariableButton); 0118 connect(m_environmentProfileModel, &EnvironmentProfileModel::dataChanged, 0119 this, &EnvironmentWidget::changed); 0120 connect(m_environmentProfileModel, &EnvironmentProfileModel::rowsInserted, 0121 this, &EnvironmentWidget::changed); 0122 connect(m_environmentProfileModel, &EnvironmentProfileModel::rowsRemoved, 0123 this, &EnvironmentWidget::changed); 0124 } 0125 0126 void EnvironmentWidget::selectProfile(const QString& profileName) 0127 { 0128 const int profileIndex = m_environmentProfileListModel->profileIndex(profileName); 0129 if (profileIndex < 0) { 0130 return; 0131 } 0132 ui.profileSelect->setCurrentIndex(profileIndex); 0133 } 0134 0135 void EnvironmentWidget::updateDeleteVariableButton() 0136 { 0137 const auto selectedRows = ui.variableTable->selectionModel()->selectedRows(); 0138 ui.removeVariableButton->setEnabled(!selectedRows.isEmpty()); 0139 } 0140 0141 void EnvironmentWidget::setSelectedProfileAsDefault() 0142 { 0143 const int selectedIndex = ui.profileSelect->currentIndex(); 0144 m_environmentProfileListModel->setDefaultProfile(selectedIndex); 0145 } 0146 0147 void EnvironmentWidget::loadSettings( KConfig* config ) 0148 { 0149 qCDebug(SHELL) << "Loading profiles from config"; 0150 m_environmentProfileListModel->loadFromConfig(config); 0151 0152 const int defaultProfileIndex = m_environmentProfileListModel->defaultProfileIndex(); 0153 ui.profileSelect->setCurrentIndex(defaultProfileIndex); 0154 } 0155 0156 void EnvironmentWidget::saveSettings( KConfig* config ) 0157 { 0158 m_environmentProfileListModel->saveToConfig(config); 0159 } 0160 0161 void EnvironmentWidget::defaults( KConfig* config ) 0162 { 0163 loadSettings( config ); 0164 } 0165 0166 QString EnvironmentWidget::askNewProfileName(const QString& defaultName) 0167 { 0168 ScopedDialog<QDialog> dialog(this); 0169 dialog->setWindowTitle(i18nc("@title:window", "Enter Name of New Environment Profile")); 0170 0171 auto *layout = new QVBoxLayout(dialog); 0172 0173 auto editLayout = new QHBoxLayout; 0174 0175 auto label = new QLabel(i18nc("@label:textbox", "Name:")); 0176 editLayout->addWidget(label); 0177 auto edit = new QLineEdit; 0178 editLayout->addWidget(edit); 0179 layout->addLayout(editLayout); 0180 0181 auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 0182 auto okButton = buttonBox->button(QDialogButtonBox::Ok); 0183 okButton->setEnabled(false); 0184 okButton->setDefault(true); 0185 dialog->connect(buttonBox, &QDialogButtonBox::accepted, dialog.data(), &QDialog::accept); 0186 dialog->connect(buttonBox, &QDialogButtonBox::rejected, dialog.data(), &QDialog::reject); 0187 layout->addWidget(buttonBox); 0188 0189 auto validator = new ProfileNameValidator(m_environmentProfileListModel, dialog); 0190 connect(edit, &QLineEdit::textChanged, validator, [validator, okButton](const QString& text) { 0191 int pos; 0192 QString t(text); 0193 const bool isValidProfileName = (validator->validate(t, pos) == QValidator::Acceptable); 0194 okButton->setEnabled(isValidProfileName); 0195 }); 0196 0197 edit->setText(defaultName); 0198 edit->selectAll(); 0199 0200 if (dialog->exec() != QDialog::Accepted) { 0201 return {}; 0202 } 0203 0204 return edit->text(); 0205 } 0206 0207 void EnvironmentWidget::removeSelectedVariables() 0208 { 0209 const auto selectedRows = ui.variableTable->selectionModel()->selectedRows(); 0210 if (selectedRows.isEmpty()) { 0211 return; 0212 } 0213 0214 QStringList variables; 0215 variables.reserve(selectedRows.size()); 0216 for (const auto& idx : selectedRows) { 0217 const QString variable = idx.data(EnvironmentProfileModel::VariableRole).toString(); 0218 variables << variable; 0219 } 0220 0221 m_environmentProfileModel->removeVariables(variables); 0222 } 0223 0224 void EnvironmentWidget::onVariableInserted(int column, const QVariant& value) 0225 { 0226 Q_UNUSED(column); 0227 m_environmentProfileModel->addVariable(value.toString(), QString()); 0228 } 0229 0230 void EnvironmentWidget::batchModeEditButtonClicked() 0231 { 0232 ScopedDialog<QDialog> dialog(this); 0233 dialog->setWindowTitle( i18nc("@title:window", "Batch Edit Mode" ) ); 0234 0235 auto *layout = new QVBoxLayout(dialog); 0236 0237 auto edit = new QPlainTextEdit; 0238 edit->setPlaceholderText(QStringLiteral("VARIABLE1=VALUE1\nVARIABLE2=VALUE2")); 0239 QString text; 0240 for (int i = 0; i < m_proxyModel->rowCount(); ++i) { 0241 const auto variable = m_proxyModel->index(i, EnvironmentProfileModel::VariableColumn).data().toString(); 0242 const auto value = m_proxyModel->index(i, EnvironmentProfileModel::ValueColumn).data().toString(); 0243 text.append(variable + QLatin1Char('=') + value + QLatin1Char('\n')); 0244 } 0245 edit->setPlainText(text); 0246 layout->addWidget( edit ); 0247 0248 auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); 0249 auto okButton = buttonBox->button(QDialogButtonBox::Ok); 0250 okButton->setDefault(true); 0251 okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0252 dialog->connect(buttonBox, &QDialogButtonBox::accepted, dialog.data(), &QDialog::accept); 0253 dialog->connect(buttonBox, &QDialogButtonBox::rejected, dialog.data(), &QDialog::reject); 0254 layout->addWidget(buttonBox); 0255 0256 dialog->resize(600, 400); 0257 0258 if ( dialog->exec() != QDialog::Accepted ) { 0259 return; 0260 } 0261 0262 m_environmentProfileModel->setVariablesFromString(edit->toPlainText()); 0263 } 0264 0265 void EnvironmentWidget::addProfile() 0266 { 0267 const auto profileName = askNewProfileName(QString()); 0268 if (profileName.isEmpty()) { 0269 return; 0270 } 0271 0272 const int profileIndex = m_environmentProfileListModel->addProfile(profileName); 0273 0274 ui.profileSelect->setCurrentIndex(profileIndex); 0275 ui.variableTable->setFocus(Qt::OtherFocusReason); 0276 } 0277 0278 void EnvironmentWidget::cloneSelectedProfile() 0279 { 0280 const int currentIndex = ui.profileSelect->currentIndex(); 0281 const auto currentProfileName = m_environmentProfileListModel->profileName(currentIndex); 0282 // pass original name as starting name, as the user might want to enter a variant of it 0283 const auto profileName = askNewProfileName(currentProfileName); 0284 if (profileName.isEmpty()) { 0285 return; 0286 } 0287 0288 const int profileIndex = m_environmentProfileListModel->cloneProfile(profileName, currentProfileName); 0289 0290 ui.profileSelect->setCurrentIndex(profileIndex); 0291 ui.variableTable->setFocus(Qt::OtherFocusReason); 0292 } 0293 0294 void EnvironmentWidget::removeSelectedProfile() 0295 { 0296 if (ui.profileSelect->count() <= 1) { 0297 return; 0298 } 0299 0300 const int selectedProfileIndex = ui.profileSelect->currentIndex(); 0301 0302 m_environmentProfileListModel->removeProfile(selectedProfileIndex); 0303 0304 const int defaultProfileIndex = m_environmentProfileListModel->defaultProfileIndex(); 0305 ui.profileSelect->setCurrentIndex(defaultProfileIndex); 0306 } 0307 0308 void EnvironmentWidget::onDefaultProfileChanged(int defaultProfileIndex) 0309 { 0310 const int selectedProfileIndex = ui.profileSelect->currentIndex(); 0311 const bool isDefaultProfile = (defaultProfileIndex == selectedProfileIndex); 0312 0313 ui.removeProfileButton->setEnabled(ui.profileSelect->count() > 1 && !isDefaultProfile); 0314 ui.setAsDefaultProfileButton->setEnabled(!isDefaultProfile); 0315 } 0316 0317 void EnvironmentWidget::onSelectedProfileChanged(int selectedProfileIndex) 0318 { 0319 const auto selectedProfileName = m_environmentProfileListModel->profileName(selectedProfileIndex); 0320 m_environmentProfileModel->setCurrentProfile(selectedProfileName); 0321 0322 const bool isDefaultProfile = (m_environmentProfileListModel->defaultProfileIndex() == selectedProfileIndex); 0323 0324 ui.removeProfileButton->setEnabled(ui.profileSelect->count() > 1 && !isDefaultProfile); 0325 ui.setAsDefaultProfileButton->setEnabled(!isDefaultProfile); 0326 } 0327 0328 #include "environmentwidget.moc" 0329 #include "moc_environmentwidget.cpp"