1 /**********************************************************************************************
2 Copyright (C) 2017 Oliver Eichler <oliver.eichler@gmx.de>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 **********************************************************************************************/
18
19 #include "helpers/CSettings.h"
20 #include "widgets/CTemplateWidget.h"
21
22 #include <QtGui>
23 #include <QtUiTools>
24 #include <QtWidgets>
25
CTemplateWidget(QWidget * parent)26 CTemplateWidget::CTemplateWidget(QWidget* parent)
27 : QDialog(parent)
28 {
29 setupUi(this);
30 connect(comboTemplates, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &CTemplateWidget::slotTemplateActivated);
31 connect(pushPreview, &QPushButton::pressed, this, &CTemplateWidget::slotPreview);
32 connect(toolPathTemplates, &QToolButton::pressed, this, &CTemplateWidget::slotSetPath);
33 listTemplates();
34 }
35
36
listTemplates()37 void CTemplateWidget::listTemplates()
38 {
39 comboTemplates->clear();
40 comboTemplates->addItem(tr("choose one..."));
41 comboTemplates->addItem(tr("Cycling Tour Summary (built-in)"), "://templates/Cycling_Tour_Summary.ui");
42 comboTemplates->addItem(tr("Hiking Tour Summary (built-in)"), "://templates/Hiking_Tour_Summary.ui");
43 comboTemplates->addItem(tr("Hiking Tour Summary - Advanced (built-in)"), "://templates/Hiking_Tour_Summary_(Advanced).ui");
44 comboTemplates->addItem(tr("Running Summary (built-in)"), "://templates/Running_Summary.ui");
45
46 SETTINGS;
47 const QString& path = cfg.value("TextEditWidget/templatePath", "").toString();
48
49 if(!path.isEmpty())
50 {
51 QDir dir(path);
52 const QStringList& files = dir.entryList(QStringList("*.ui"), QDir::Files);
53 for(const QString& file : files)
54 {
55 QString name = QFileInfo(file).completeBaseName().replace("_", " ");
56 comboTemplates->addItem(name, dir.absoluteFilePath(file));
57 }
58 }
59
60 const QString& data = cfg.value("TextEditWidget/template", "").toString();
61 const int idx = comboTemplates->findData(data);
62 if(idx != -1)
63 {
64 comboTemplates->setCurrentIndex(idx);
65 }
66 }
67
text()68 QString CTemplateWidget::text()
69 {
70 if(widget.isNull())
71 {
72 return "";
73 }
74 QString str;
75
76 QList<QGroupBox*> groups = widget->findChildren<QGroupBox*>(QRegExp("group.*"), Qt::FindDirectChildrenOnly);
77 qSort(groups.begin(), groups.end(), [](const QGroupBox* g1, const QGroupBox* g2){return g1->objectName() < g2->objectName(); });
78
79 for(const QGroupBox* group : qAsConst(groups))
80 {
81 str += QString("<p><b>%1</b>: ").arg(group->title());
82 str += resolveGroup(group);
83 str += "</p>";
84 }
85
86 return str;
87 }
88
resolveGroup(const QGroupBox * group)89 QString CTemplateWidget::resolveGroup(const QGroupBox* group)
90 {
91 QString str;
92 QList<QWidget*> widgets = group->findChildren<QWidget*>(QRegExp(".*"), Qt::FindDirectChildrenOnly);
93 qSort(widgets.begin(), widgets.end(), [](const QWidget* w1, const QWidget* w2){return w1->property("order") < w2->property("order"); });
94
95 for(const QWidget* w : qAsConst(widgets))
96 {
97 const QString pre(str.isEmpty() ? "" : ", ");
98
99 {
100 const QCheckBox* obj = dynamic_cast<const QCheckBox*>(w);
101 if(obj != nullptr)
102 {
103 if(obj->isChecked())
104 {
105 str += pre + obj->text().replace("&", "");
106 }
107 continue;
108 }
109 }
110
111 {
112 const QRadioButton* obj = dynamic_cast<const QRadioButton*>(w);
113 if(obj != nullptr)
114 {
115 if(obj->isChecked())
116 {
117 str += pre + obj->text().replace("&", "");
118 }
119 continue;
120 }
121 }
122
123 {
124 const QComboBox* obj = dynamic_cast<const QComboBox*>(w);
125 if(obj != nullptr)
126 {
127 if(!obj->currentText().isEmpty())
128 {
129 str += pre + obj->currentText();
130 }
131 continue;
132 }
133 }
134
135 {
136 const QLineEdit* obj = dynamic_cast<const QLineEdit*>(w);
137 if(obj != nullptr)
138 {
139 if(!obj->text().simplified().isEmpty())
140 {
141 str += pre + obj->text();
142 }
143 continue;
144 }
145 }
146
147 {
148 const QTextEdit* obj = dynamic_cast<const QTextEdit*>(w);
149 if(obj != nullptr)
150 {
151 if(!obj->toPlainText().simplified().isEmpty())
152 {
153 str += pre + obj->toHtml();
154 }
155 continue;
156 }
157 }
158 }
159
160 if(str.isEmpty())
161 {
162 str += tr("-");
163 }
164
165 return str;
166 }
167
slotSetPath()168 void CTemplateWidget::slotSetPath()
169 {
170 SETTINGS;
171 QString path = cfg.value("TextEditWidget/templatePath", QDir::homePath()).toString();
172 path = QFileDialog::getExistingDirectory(this, tr("Template path..."), path);
173 if(path.isEmpty())
174 {
175 return;
176 }
177 cfg.setValue("TextEditWidget/templatePath", path);
178 listTemplates();
179 }
180
slotTemplateActivated(int idx)181 void CTemplateWidget::slotTemplateActivated(int idx)
182 {
183 delete widget;
184 if(idx < 1)
185 {
186 pushPreview->setEnabled(false);
187 buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
188 return;
189 }
190
191 bool success = false;
192 const QString& filename = comboTemplates->itemData(idx).toString();
193 QFile file(filename);
194 if(!file.open(QFile::ReadOnly))
195 {
196 widget = new QLabel(tr("Failed to read template file %1.").arg(filename));
197 }
198 else
199 {
200 QUiLoader loader;
201 widget = loader.load(&file, this);
202 file.close();
203
204 if(widget.isNull())
205 {
206 widget = new QLabel(loader.errorString());
207 }
208 else if(nextInFocusChain() != nullptr)
209 {
210 // convert focus chain into a sortable property.
211 quint32 cnt = 0;
212 QWidget* first = nextInFocusChain();
213 QWidget* next = first;
214 do
215 {
216 if( (dynamic_cast<QCheckBox*>(next) != nullptr)
217 || (dynamic_cast<QRadioButton*>(next) != nullptr)
218 || (dynamic_cast<QComboBox*>(next) != nullptr)
219 || (dynamic_cast<QLineEdit*>(next) != nullptr)
220 || (dynamic_cast<QTextEdit*>(next) != nullptr)
221 )
222 {
223 next->setProperty("order", cnt++);
224 }
225
226 next = next->nextInFocusChain();
227 }
228 while(next && next != first);
229
230 success = true;
231 }
232 }
233
234 layoutWidget->insertWidget(0, widget);
235 pushPreview->setEnabled(success);
236 buttonBox->button(QDialogButtonBox::Ok)->setEnabled(success);
237
238 SETTINGS;
239 cfg.setValue("TextEditWidget/template", filename);
240
241 adjustSize();
242 }
243
slotPreview()244 void CTemplateWidget::slotPreview()
245 {
246 QTextBrowser* preview = new QTextBrowser();
247
248 preview->setAttribute(Qt::WA_DeleteOnClose, true);
249 preview->setWindowModality(Qt::ApplicationModal);
250 preview->setReadOnly(true);
251 preview->setHtml(text());
252 preview->setWindowTitle(tr("Preview..."));
253
254 preview->setMinimumWidth(600);
255 preview->move(QApplication::desktop()->screen()->rect().center() - preview->rect().center());
256 preview->show();
257 preview->raise();
258
259 QAction* action = new QAction(preview);
260 action->setShortcut(Qt::Key_Escape);
261
262 preview->addAction(action);
263 connect(action, &QAction::triggered, preview, &QTextBrowser::close);
264 }
265