ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
PythonRuntimeSettings.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 #include "Resources.h"
10 
11 #include <ui_PathVariableEditor.h>
12 #include <ui_PythonRuntimeSettings.h>
13 
14 #include <QDialogButtonBox>
15 #include <QFileDialog>
16 #include <QIcon>
17 #include <QLineEdit>
18 #include <QMessageBox>
19 #include <QPushButton>
20 #include <QSettings>
21 #include <QStringListModel>
22 #include <QtGlobal>
23 
24 #include <memory>
25 
28 class PathVariableInputDialog final : public QDialog
29 {
30  public:
31  explicit PathVariableInputDialog(QWidget *parent = nullptr)
32  : QDialog(parent),
33  m_pathEdit(new QLineEdit),
34  m_selectPathBtn(new QPushButton),
35  m_dialogBtnBox(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel))
36  {
37  m_selectPathBtn->setText(QStringLiteral("..."));
38  connect(m_selectPathBtn,
39  &QPushButton::clicked,
40  this,
41  &PathVariableInputDialog::handleSelectPath);
42 
43  connect(m_dialogBtnBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
44  connect(m_dialogBtnBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
45 
46  auto *layout = new QHBoxLayout;
47  layout->addWidget(m_pathEdit);
48  layout->addWidget(m_selectPathBtn);
49 
50  auto layout1 = new QVBoxLayout;
51  layout1->addLayout(layout);
52  layout1->addWidget(m_dialogBtnBox);
53 
54  setLayout(layout1);
55  }
56 
57  QString selectedPath() const
58  {
59  return m_pathEdit->text();
60  }
61 
62  private:
63  void handleSelectPath()
64  {
65  QString selectedDir = QFileDialog::getExistingDirectory(
66  this,
67  tr("Select a path to add"),
68  QString(),
69  QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
70  m_pathEdit->setText(selectedDir);
71  }
72 
73  private:
74  QLineEdit *m_pathEdit;
75  QPushButton *m_selectPathBtn;
76  QDialogButtonBox *m_dialogBtnBox;
77 };
78 
81 class PathVariableEditor final : public QDialog
82 {
83  public:
84  explicit PathVariableEditor(const QStringList &values, QWidget *parent = nullptr)
85  : QDialog(parent), m_model(new QStringListModel), m_ui(new Ui_PathVariableEditor)
86  {
87  m_ui->setupUi(this);
88  m_model->setStringList(values);
89  m_ui->valuesView->setModel(m_model);
90  connect(m_ui->addButton, &QPushButton::clicked, this, &PathVariableEditor::handleAdd);
91  connect(m_ui->deleteButton, &QPushButton::clicked, this, &PathVariableEditor::handleDelete);
92  }
93 
94  QStringList stringList() const
95  {
96  return m_model->stringList();
97  }
98 
99  private:
100  void handleAdd()
101  {
102 
103  PathVariableInputDialog dlg(this);
104  dlg.exec();
105  QString path = dlg.selectedPath();
106 
107  if (!path.isEmpty())
108  {
109  int rowCount = m_model->rowCount();
110  m_model->insertRows(rowCount, 1);
111  m_model->setData(m_model->index(rowCount), path);
112  }
113  }
114 
115  void handleDelete()
116  {
117  const QModelIndex index = m_ui->valuesView->currentIndex();
118  m_model->removeRow(index.row());
119  }
120 
121  private:
122  QStringListModel *m_model;
123  Ui_PathVariableEditor *m_ui;
124 };
125 
126 static std::unique_ptr<QSettings> LoadOurSettings()
127 {
128  return std::make_unique<QSettings>(
129  QCoreApplication::organizationName(),
130  QCoreApplication::applicationName().append(":PythonRuntime.Settings"));
131 }
132 
134  : QDialog(parent), m_ui(new Ui_PythonRuntimeSettings)
135 {
136  m_ui->setupUi(this);
137  m_ui->localEnvSettingsWidget->hide();
138  m_ui->envTypeComboBox->addItem("Bundled");
139 #if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
140  m_ui->envTypeComboBox->addItem("System");
141 #endif
142  m_ui->envTypeComboBox->addItem("Local");
143  setWindowIcon(QIcon(SETTINGS_ICON_PATH));
144 
145  connect(this, &QDialog::accepted, this, &PythonRuntimeSettings::saveSettings);
146  connect(this, &QDialog::accepted, this, [this]() { m_ui->informationLabel->hide(); });
147  connect(this, &QDialog::rejected, this, [this]() { m_ui->informationLabel->hide(); });
148  connect(m_ui->editButton,
149  &QPushButton::clicked,
150  this,
151  &PythonRuntimeSettings::handleEditPluginsPaths);
152  connect(m_ui->envTypeComboBox,
153  &QComboBox::currentTextChanged,
154  this,
155  &PythonRuntimeSettings::handleEnvComboBoxChange);
156  connect(m_ui->localEnvSelectBtn,
157  &QPushButton::clicked,
158  this,
159  &PythonRuntimeSettings::handleSelectLocalEnv);
160  restoreSettings();
161  m_ui->informationLabel->hide();
162 }
163 
164 QString PythonRuntimeSettings::selectedEnvType() const
165 {
166  return m_ui->envTypeComboBox->currentText();
167 }
168 
169 QString PythonRuntimeSettings::localEnvPath() const
170 {
171  if (selectedEnvType() == "Local")
172  {
173  return m_ui->localEnvPathLabel->text();
174  }
175  return {};
176 }
177 
178 void PythonRuntimeSettings::restoreSettings()
179 {
180  std::unique_ptr<QSettings> settings = LoadOurSettings();
181  m_pluginsPaths = settings->value(QStringLiteral("PluginPaths")).value<QStringList>();
182 
183  const QString envType = settings->value(QStringLiteral("EnvType")).toString();
184  int index = m_ui->envTypeComboBox->findText(envType);
185  index = (index == -1) ? 0 : index;
186  m_ui->envTypeComboBox->setCurrentIndex(index);
187 
188  if (selectedEnvType() == "Local")
189  {
190  const QString localEnvPath = settings->value(QStringLiteral("EnvPath")).toString();
191  m_ui->localEnvPathLabel->setText(localEnvPath);
192  }
193 }
194 
195 void PythonRuntimeSettings::saveSettings() const
196 {
197  std::unique_ptr<QSettings> settings = LoadOurSettings();
198  settings->setValue(QStringLiteral("PluginPaths"), pluginsPaths());
199  settings->setValue(QStringLiteral("EnvType"), selectedEnvType());
200  settings->setValue(QStringLiteral("EnvPath"), localEnvPath());
201 }
202 
203 void PythonRuntimeSettings::handleEditPluginsPaths()
204 {
205  PathVariableEditor editor(pluginsPaths(), this);
206  editor.exec();
207  m_pluginsPaths = editor.stringList();
208  m_ui->informationLabel->show();
209 }
210 
211 void PythonRuntimeSettings::handleEnvComboBoxChange(const QString &envTypeName)
212 {
213  if (envTypeName == "Local")
214  {
215  m_ui->localEnvSettingsWidget->show();
216  }
217  else
218  {
219  m_ui->localEnvSettingsWidget->hide();
220  }
221  m_ui->informationLabel->show();
222 }
223 
224 void PythonRuntimeSettings::handleSelectLocalEnv()
225 {
226  QString selectedDir = QFileDialog::getExistingDirectory(this, "Python Environment Root");
227  if (!selectedDir.isEmpty())
228  {
229  PythonConfig config;
230  config.initFromLocation(selectedDir);
231 
232  bool isEnvValid = config.validateAndDisplayErrors(this);
233  if (!isEnvValid)
234  {
235  m_ui->envTypeComboBox->setCurrentIndex(0);
236  }
237  else
238  {
239  m_ui->localEnvPathLabel->setText(selectedDir);
240  }
241  }
242 }
243 
245 {
246  return m_pluginsPaths;
247 }
248 
250 {
251  if (selectedEnvType() == "System")
252  {
253  PythonConfig config;
254  config.initDefault();
255  return config;
256  }
257  else if (selectedEnvType() == "Bundled")
258  {
259  PythonConfig config;
260  config.initBundled();
261  return config;
262  }
263  else if (selectedEnvType() == "Local")
264  {
265  PythonConfig config;
266  config.initFromLocation(localEnvPath());
267  return config;
268  }
269  else
270  {
271  Q_ASSERT(false);
272  return {};
273  }
274 }
275 
277 {
278  return m_ui->envTypeComboBox->currentIndex() == 0;
279 }
static std::unique_ptr< QSettings > LoadOurSettings()
#define SETTINGS_ICON_PATH
Definition: Resources.h:23
PathVariableEditor(const QStringList &values, QWidget *parent=nullptr)
QStringList stringList() const
PathVariableInputDialog(QWidget *parent=nullptr)
void initBundled()
bool validateAndDisplayErrors(QWidget *parent=nullptr) const
void initFromLocation(const QString &prefix)
void initDefault()
PythonRuntimeSettings(QWidget *parent=nullptr)
QStringList pluginsPaths() const
PythonConfig pythonEnvConfig() const
static const std::string path
Definition: PointCloud.cpp:59
std::string toString(T x)
Definition: Common.h:80