2 Copyright (C) 2013-2024 Ben Kibbey <bjk@luxsci.net>
4 This file is part of qpwmc.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 #include <QButtonGroup>
22 #include <QPushButton>
25 #include <QMessageBox>
26 #include <QCalendarWidget>
28 #include "pwmdMainWindow.h"
29 #include "pwmdSocketDialog.h"
30 #include "applicationForm.h"
31 #include "applicationFormXmlStream.h"
32 #include "applicationFormRadioButton.h"
33 #include "applicationFormPage.h"
34 #include "applicationFormFileSelector.h"
35 #include "applicationFormFinalizePage.h"
36 #include "applicationFormGeneratePassword.h"
37 #include "applicationFormExpiryButton.h"
38 #include "applicationFormDateSelector.h"
39 #include "pwmdExpireDialog.h"
41 ApplicationForm::ApplicationForm (Pwmd
*pwmHandle
, const QString
&filename
,
42 PwmdTreeWidget
*w
, PwmdMainWindow
*p
)
48 QAbstractButton
*pb
= button (QWizard::CancelButton
);
49 connect (pb
, SIGNAL (clicked (bool)), this, SLOT (slotCancel (bool)));
53 SIGNAL (currentItemChanged (QTreeWidgetItem
*, QTreeWidgetItem
*)),
55 SLOT (slotFormElementSelected (QTreeWidgetItem
*, QTreeWidgetItem
*)));
63 ApplicationForm::setModified ()
69 ApplicationForm::modified ()
75 ApplicationForm::slotCancel (bool)
80 ApplicationForm::ApplicationForm (const QString
&filename
,
81 QString socket
, QString dataFilename
,
82 QString path
) : QWizard ()
84 QAbstractButton
*pb
= button (QWizard::CancelButton
);
85 connect (pb
, SIGNAL (clicked (bool)), this, SLOT (slotCancel (bool)));
86 elementTree
= nullptr;
90 _dataFilename
= dataFilename
;
95 ApplicationForm::ApplicationForm (const QString
&filename
) : QWizard ()
97 QAbstractButton
*pb
= button (QWizard::CancelButton
);
98 connect (pb
, SIGNAL (clicked (bool)), this, SLOT (slotCancel (bool)));
100 elementTree
= nullptr;
106 ApplicationForm::slotAccepted ()
111 ApplicationForm::slotFormElementSelected (QTreeWidgetItem
* item
,
112 QTreeWidgetItem
* old
)
115 foreach (ApplicationFormWidget
*w
, stream
->widgets ())
117 if (w
->id () == "pwmdRootElement")
119 w
->setValue (parent
->elementPath (item
, "<TAB>"));
126 ApplicationForm::addFormRow (QFormLayout
*fl
, QHBoxLayout
*hb
,
127 ApplicationFormWidget
*w
, QWizardPage
*wp
,
130 if (w
->isRequired () && w
->widget ())
132 connect (w
->widget (), SIGNAL (textChanged (const QString
&)), wp
,
133 SIGNAL (completeChanged ()));
136 QLabel
*l
= new QLabel (w
->label ());
137 l
->setWhatsThis (w
->whatsThis ());
138 widgetsToDelete
.append (l
);
141 fl
->addRow (withLabel
? l
: 0, hb
);
143 fl
->addRow (withLabel
? l
: 0, w
->widget ());
147 ApplicationForm::setHasError (bool b
)
153 ApplicationForm::hasError ()
159 ApplicationForm::slotPageChanged (int n
)
162 finalPage
->commit ();
166 ApplicationForm::slotChangeExpiry ()
168 QWidget
*fw
= QApplication::focusWidget ();
169 ApplicationFormExpiryButton
*pb
= static_cast<ApplicationFormExpiryButton
*>(fw
);
170 ApplicationFormWidget
*w
= pb
->formWidget ();
171 PwmdExpireDialog
*d
= new PwmdExpireDialog (w
->expiryDate (),
172 w
->expiryAge (), this);
175 w
->setExpiry (d
->expire (), d
->increment ());
181 ApplicationForm::addExpiry (ApplicationFormWidget
*w
, QHBoxLayout
*hb
)
183 if (hb
&& w
&& w
->expiry ())
185 ApplicationFormExpiryButton
*pb
= new ApplicationFormExpiryButton (w
);
187 pb
->setIcon (QIcon (":icons/expiry.svg"));
189 connect (pb
, SIGNAL (clicked ()), this, SLOT (slotChangeExpiry ()));
194 ApplicationForm::slotDateSelector (const QDate
&d
)
196 foreach (ApplicationFormWidget
*w
, stream
->widgets ())
198 if (w
->dateSelector ())
200 ApplicationFormDateSelector
*s
= qobject_cast
<ApplicationFormDateSelector
*> (w
->widget ());
207 ApplicationForm::doForm (const QString
&filename
)
209 setWindowFlags (Qt::WindowTitleHint
);
210 setWindowTitle (tr ("Pwmd Application Form"));
215 QRegularExpression
rx ("^[!]?[^!\\s][^\\s]*");
216 lineEditValidator
= new QRegularExpressionValidator (rx
, this);
218 connect (this, SIGNAL (currentIdChanged (int)), this, SLOT (slotPageChanged (int)));
219 connect (this, SIGNAL (accepted ()), this, SLOT (slotAccepted ()));
221 stream
= new ApplicationFormXmlStream (filename
, this);
222 if (stream
->error () != QXmlStreamReader::NoError
)
228 QList
<ApplicationFormWidget
*> widgets
= stream
->widgets ();
229 int radioButtonId
= 0;
230 ApplicationFormPage
*wp
= new ApplicationFormPage ();
231 QFormLayout
*fl
= new QFormLayout (wp
);
233 wp
->setWidgets (widgets
);
235 foreach (ApplicationFormWidget
*w
, widgets
)
237 QHBoxLayout
*hb
= new QHBoxLayout ();
238 bool withLabel
= true;
240 if (w
->type () == ApplicationFormWidget::AppWidgetRadioButton
)
242 QButtonGroup
*bg
= new QButtonGroup ();
243 QStringList rbs
= w
->radioButtons ();
245 widgetsToDelete
.append (bg
);
247 for (int n
= 0; n
< rbs
.count (); n
++)
249 ApplicationFormRadioButton
*rb
= new ApplicationFormRadioButton (rbs
.at (n
));
253 rb
->setId (radioButtonId
);
254 w
->addRadioButtonId (radioButtonId
++);
255 connect (rb
, SIGNAL (clicked (bool)), this,
256 SLOT (slotRadioButtonClicked (bool)));
258 if (w
->value () == rbs
.at (n
))
259 rb
->setChecked (true);
263 if (w
->elementSelector ())
267 hb
->addWidget (elementTree
);
268 addFormRow (fl
, hb
, w
, wp
, true);
269 hb
= new QHBoxLayout ();
270 hb
->addWidget (w
->widget ());
271 QLineEdit
*le
= static_cast <QLineEdit
*> (w
->widget ());
272 le
->setPlaceholderText (tr ("Enter or select from above..."));
277 QPushButton
*pb
= new QPushButton ();
278 pb
->setText (tr ("Select"));
279 hb
->addWidget (w
->widget ());
281 if (w
->id () == "pwmdSocket")
282 connect (pb
, SIGNAL (clicked ()), this,
283 SLOT (slotSocketSelector ()));
285 connect (pb
, SIGNAL (clicked ()), this,
286 SLOT (slotElementSelector ()));
289 else if (w
->dateSelector ())
291 QCalendarWidget
*cal
= new QCalendarWidget ();
292 connect (cal
, SIGNAL (clicked (const QDate
&)), this,
293 SLOT (slotDateSelector (const QDate
&)));
295 addFormRow (fl
, hb
, w
, wp
, true);
296 hb
= new QHBoxLayout ();
297 hb
->addWidget (w
->widget ());
298 ApplicationFormDateSelector
*le
= static_cast <ApplicationFormDateSelector
*> (w
->widget ());
299 le
->setText (w
->value ());
302 else if (w
->fileSelector ())
304 ApplicationFormFileSelector
*pb
= new ApplicationFormFileSelector (w
->widget (), this);
305 pb
->setText (tr ("Select"));
306 hb
->addWidget (w
->widget ());
308 connect (pb
, SIGNAL (clicked ()), pb
, SLOT (slotFileSelector ()));
310 else if (w
->passwordGenerator ())
312 ApplicationFormGeneratePassword
*pb
= new ApplicationFormGeneratePassword (w
, this);
313 pb
->setText (tr ("Generate"));
314 hb
->addWidget (w
->widget ());
316 connect (pb
, SIGNAL (clicked ()), pb
, SLOT (slotGeneratePassword ()));
318 else if (w
->widget ())
319 hb
->addWidget (w
->widget ());
321 if (w
->type () == ApplicationFormWidget::AppWidgetLineEdit
)
323 /* This QLineEdit creates an element from its value. Not a perfect
325 if (w
->pwmdName ().isEmpty ())
327 QLineEdit
*le
= static_cast<QLineEdit
*>(w
->widget ());
328 le
->setValidator (lineEditValidator
);
333 addFormRow (fl
, hb
, w
, wp
, withLabel
);
336 wp
->setTitle (ui
.wz_start
->title ());
337 wp
->setSubTitle (ui
.wz_start
->subTitle ());
340 slotFormElementSelected (elementTree
->currentItem (), nullptr);
342 slotDateSelector (QDate::currentDate ());
344 finalPage
= new ApplicationFormFinalizePage ();
345 finalPage
->setTitle (ui
.wz_start
->title ());
346 finalPage
->setSubTitle (ui
.wz_start
->subTitle ());
347 finalPage
->setHandle (pwm
);
348 updateForm (_dataFilename
, _elementPath
, _socket
);
353 ApplicationForm::socket ()
355 QString s
= QString ();
357 foreach (ApplicationFormWidget
*w
, stream
->widgets ())
359 if (w
->id () == "pwmdSocket")
361 QLineEdit
*le
= static_cast<QLineEdit
*>(w
->widget ());
363 w
->setValue (le
->text ());
372 ApplicationForm::filename ()
374 QString s
= QString ();
376 foreach (ApplicationFormWidget
*w
, stream
->widgets ())
378 if (w
->id () == "pwmdFilename")
380 QLineEdit
*le
= static_cast<QLineEdit
*>(w
->widget ());
382 w
->setValue (le
->text ());
391 ApplicationForm::elementPath ()
393 QString s
= QString ();
395 foreach (ApplicationFormWidget
*w
, stream
->widgets ())
397 if (w
->id () == "pwmdRootElement")
405 ApplicationForm::updateForm (QString filename
, QString element
, QString sock
)
407 foreach (ApplicationFormWidget
*w
, stream
->widgets ())
409 if (w
->id () == "pwmdFilename" && !filename
.isEmpty ())
410 w
->setValue (filename
);
411 else if (w
->id () == "pwmdRootElement" && !element
.isEmpty ())
412 w
->setValue (element
.replace ("\t", "<TAB>"));
413 else if (w
->id () == "pwmdSocket" && !sock
.isEmpty ())
419 ApplicationForm::keyPressEvent (QKeyEvent
*ev
)
421 if (ev
->key () == Qt::Key_Escape
)
424 QDialog::keyPressEvent (ev
);
428 ApplicationForm::slotKnownHostCallback (void *data
, const char *host
,
429 const char *key
, size_t len
)
431 gpg_error_t rc
= Pwmd::knownHostPrompt (data
, host
, key
, len
);
432 setHasError (rc
!= 0);
433 emit
knownHostRc (rc
);
437 ApplicationForm::slotElementSelector ()
440 bool notFound
= false;
441 QString filename
= buildElementPath (QString (), "pwmdFilename", notFound
);
442 QString rootElement
= buildElementPath (QString (), "pwmdRootElement",
444 QString sock
= buildElementPath (QString (), "pwmdSocket", notFound
);
446 bool ownHandle
= false;
451 pwm
= new Pwmd (0, 0, 0, this);
452 connect (pwm
, SIGNAL (knownHost (void *, const char *, const char *, size_t)), this, SLOT (slotKnownHostCallback (void *, const char *, const char *, size_t)));
455 if (pwm
->spawnEditor (result
, sock
, filename
, rootElement
, false))
457 sock
= Pwmd::extractToken (result
, "<SOCKET>", n
);
458 filename
= Pwmd::extractToken (result
, "<FILE>", n
);
459 rootElement
= Pwmd::extractToken (result
, "<PATH>", n
);
460 updateForm (filename
, rootElement
, sock
);
471 ApplicationForm::slotSocketSelector ()
473 QString sock
= QString ();
475 foreach (ApplicationFormWidget
*w
, stream
->widgets ())
477 if (w
->id () == "pwmdSocket")
484 PwmdSocketDialog
*d
= new PwmdSocketDialog (sock
, this);
485 d
->setParent (this, Qt::Dialog
);
487 updateForm (QString (), QString (), d
->socket ());
493 ApplicationForm::slotRadioButtonClicked (bool b
)
496 QWidget
*fw
= QApplication::focusWidget ();
497 ApplicationFormRadioButton
*rb
= static_cast<ApplicationFormRadioButton
*>(fw
);
499 foreach (ApplicationFormWidget
*w
, stream
->widgets ())
501 if (w
->type () == ApplicationFormWidget::AppWidgetRadioButton
)
503 if (w
->hasRadioButtonId (rb
->id ()))
505 w
->setValue (rb
->text ());
512 ApplicationForm::~ApplicationForm ()
520 foreach (QObject
*w
, widgetsToDelete
)
525 if (lineEditValidator
)
526 delete lineEditValidator
;
530 ApplicationForm::buildElementPath (QString path
, QString element
,
533 foreach (ApplicationFormWidget
*w
, stream
->widgets ())
535 if (w
->id () == element
)
537 if (!w
->childOf ().isEmpty ())
539 path
= buildElementPath (path
, w
->childOf (), notFound
);
540 if (path
.isEmpty () && w
->childOf () != "pwmdRootElement")
542 qWarning ("%s: could not find parent '%s'\n",
543 element
.toUtf8 ().data (),
544 w
->childOf ().toUtf8 ().data ());
549 if (!w
->pwmdName ().isEmpty ())
551 if (!path
.isEmpty ())
553 path
.append (w
->pwmdName ());
555 else if (!w
->value ().isEmpty ())
557 if (!path
.isEmpty ())
559 path
.append (w
->value ());
564 if (!w
->pwmdName ().isEmpty ())
565 path
.append (w
->pwmdName ());
567 if (!w
->value ().isEmpty ())
569 if (!w
->pwmdName ().isEmpty ())
572 path
.append (w
->value ());