1 /*
2    SPDX-FileCopyrightText: 2013-2021 Laurent Montel <montel@kde.org>
3 
4    SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "selectiontypetreewidget.h"
8 #include "core/utils.h"
9 #include "core/xml/templateselection.h"
10 
11 #include <PimCommon/PimUtil>
12 
13 #include <QFileDialog>
14 
15 #include <KLocalizedString>
16 #include <QTemporaryFile>
17 
18 #include "gui/pimdataexportgui_debug.h"
19 #include <QHeaderView>
20 #include <QPointer>
21 #include <QTreeWidgetItem>
22 
SelectionTypeTreeWidget(bool backupData,QWidget * parent)23 SelectionTypeTreeWidget::SelectionTypeTreeWidget(bool backupData, QWidget *parent)
24     : QTreeWidget(parent)
25 {
26     initialize(backupData);
27     expandAll();
28     header()->hide();
29 }
30 
~SelectionTypeTreeWidget()31 SelectionTypeTreeWidget::~SelectionTypeTreeWidget()
32 {
33 }
34 
initialize(bool backupData)35 void SelectionTypeTreeWidget::initialize(bool backupData)
36 {
37     mKmailItem = new QTreeWidgetItem(this);
38     mKmailItem->setCheckState(0, Qt::Checked);
39     mKmailItem->setText(0, Utils::appTypeToI18n(Utils::KMail));
40     createSubItem(mKmailItem, Utils::Identity);
41     createSubItem(mKmailItem, Utils::Mails);
42     createSubItem(mKmailItem, Utils::MailTransport);
43     createSubItem(mKmailItem, Utils::Resources);
44     createSubItem(mKmailItem, Utils::Config);
45 
46     mKaddressbookItem = new QTreeWidgetItem(this);
47     mKaddressbookItem->setText(0, Utils::appTypeToI18n(Utils::KAddressBook));
48     mKaddressbookItem->setCheckState(0, Qt::Checked);
49     createSubItem(mKaddressbookItem, Utils::Resources);
50     createSubItem(mKaddressbookItem, Utils::Config);
51 
52     mKalarmItem = new QTreeWidgetItem(this);
53     mKalarmItem->setText(0, Utils::appTypeToI18n(Utils::KAlarm));
54     mKalarmItem->setCheckState(0, Qt::Checked);
55     createSubItem(mKalarmItem, Utils::Resources);
56     createSubItem(mKalarmItem, Utils::Config);
57 
58     mKorganizerItem = new QTreeWidgetItem(this);
59     mKorganizerItem->setText(0, Utils::appTypeToI18n(Utils::KOrganizer));
60     mKorganizerItem->setCheckState(0, Qt::Checked);
61     createSubItem(mKorganizerItem, Utils::Resources);
62     createSubItem(mKorganizerItem, Utils::Config);
63 
64     mKNotesItem = new QTreeWidgetItem(this);
65     mKNotesItem->setText(0, Utils::appTypeToI18n(Utils::KNotes));
66     mKNotesItem->setCheckState(0, Qt::Checked);
67     createSubItem(mKNotesItem, Utils::Resources);
68     createSubItem(mKNotesItem, Utils::Config);
69     if (!backupData) {
70         createSubItem(mKNotesItem, Utils::Data);
71     }
72 
73     mAkregatorItem = new QTreeWidgetItem(this);
74     mAkregatorItem->setText(0, Utils::appTypeToI18n(Utils::Akregator));
75     mAkregatorItem->setCheckState(0, Qt::Checked);
76     createSubItem(mAkregatorItem, Utils::Config);
77     createSubItem(mAkregatorItem, Utils::Data);
78 
79     connect(this, &SelectionTypeTreeWidget::itemChanged, this, &SelectionTypeTreeWidget::slotItemChanged);
80 }
81 
removeNotSelectedItems()82 void SelectionTypeTreeWidget::removeNotSelectedItems()
83 {
84     if (!removeNotSelectedItem(mKmailItem)) {
85         delete mKmailItem;
86         mKmailItem = nullptr;
87     }
88     if (!removeNotSelectedItem(mKalarmItem)) {
89         delete mKalarmItem;
90         mKalarmItem = nullptr;
91     }
92     if (!removeNotSelectedItem(mKaddressbookItem)) {
93         delete mKaddressbookItem;
94         mKaddressbookItem = nullptr;
95     }
96     if (!removeNotSelectedItem(mKorganizerItem)) {
97         delete mKorganizerItem;
98         mKorganizerItem = nullptr;
99     }
100     if (!removeNotSelectedItem(mKNotesItem)) {
101         delete mKNotesItem;
102         mKNotesItem = nullptr;
103     }
104     if (!removeNotSelectedItem(mAkregatorItem)) {
105         delete mAkregatorItem;
106         mAkregatorItem = nullptr;
107     }
108 }
109 
removeNotSelectedItem(QTreeWidgetItem * parent)110 bool SelectionTypeTreeWidget::removeNotSelectedItem(QTreeWidgetItem *parent)
111 {
112     for (int i = parent->childCount() - 1; i >= 0; --i) {
113         QTreeWidgetItem *item = parent->child(i);
114         if (item->checkState(0) == Qt::Unchecked) {
115             delete item;
116         }
117     }
118     bool hasChildren = (parent->childCount() != 0);
119     if (hasChildren) {
120         parent->setCheckState(0, Qt::Checked);
121     }
122     return hasChildren;
123 }
124 
storedType() const125 QHash<Utils::AppsType, Utils::importExportParameters> SelectionTypeTreeWidget::storedType() const
126 {
127     QHash<Utils::AppsType, Utils::importExportParameters> stored;
128     Utils::importExportParameters var = typeChecked(mKmailItem);
129     if (!var.isEmpty()) {
130         stored.insert(Utils::KMail, var);
131     }
132     var = typeChecked(mKalarmItem);
133     if (!var.isEmpty()) {
134         stored.insert(Utils::KAlarm, var);
135     }
136     var = typeChecked(mKaddressbookItem);
137     if (!var.isEmpty()) {
138         stored.insert(Utils::KAddressBook, var);
139     }
140     var = typeChecked(mKorganizerItem);
141     if (!var.isEmpty()) {
142         stored.insert(Utils::KOrganizer, var);
143     }
144     var = typeChecked(mKNotesItem);
145     if (!var.isEmpty()) {
146         stored.insert(Utils::KNotes, var);
147     }
148     var = typeChecked(mAkregatorItem);
149     if (!var.isEmpty()) {
150         stored.insert(Utils::Akregator, var);
151     }
152     return stored;
153 }
154 
typeChecked(QTreeWidgetItem * parent) const155 Utils::importExportParameters SelectionTypeTreeWidget::typeChecked(QTreeWidgetItem *parent) const
156 {
157     Utils::importExportParameters parameters;
158     if (parent) {
159         int numberOfStep = 0;
160         Utils::StoredTypes types = Utils::None;
161         for (int i = 0; i < parent->childCount(); ++i) {
162             QTreeWidgetItem *item = parent->child(i);
163             if (item->checkState(0) == Qt::Checked) {
164                 types |= static_cast<Utils::StoredType>(item->data(0, action).toInt());
165                 ++numberOfStep;
166             }
167         }
168         parameters.types = types;
169         parameters.numberSteps = numberOfStep;
170     }
171     return parameters;
172 }
173 
createSubItem(QTreeWidgetItem * parent,Utils::StoredType type)174 void SelectionTypeTreeWidget::createSubItem(QTreeWidgetItem *parent, Utils::StoredType type)
175 {
176     switch (type) {
177     case Utils::None:
178         break;
179     case Utils::Identity: {
180         auto item = new QTreeWidgetItem(parent);
181         item->setText(0, Utils::storedTypeToI18n(Utils::Identity));
182         item->setCheckState(0, Qt::Checked);
183         item->setData(0, action, type);
184         break;
185     }
186     case Utils::Mails: {
187         auto item = new QTreeWidgetItem(parent);
188         item->setText(0, Utils::storedTypeToI18n(Utils::Mails));
189         item->setCheckState(0, Qt::Checked);
190         item->setData(0, action, type);
191         break;
192     }
193     case Utils::MailTransport: {
194         auto item = new QTreeWidgetItem(parent);
195         item->setText(0, Utils::storedTypeToI18n(Utils::MailTransport));
196         item->setCheckState(0, Qt::Checked);
197         item->setData(0, action, type);
198         break;
199     }
200     case Utils::Resources: {
201         auto item = new QTreeWidgetItem(parent);
202         item->setText(0, Utils::storedTypeToI18n(Utils::Resources));
203         item->setCheckState(0, Qt::Checked);
204         item->setData(0, action, type);
205         break;
206     }
207     case Utils::Config: {
208         auto item = new QTreeWidgetItem(parent);
209         item->setText(0, Utils::storedTypeToI18n(Utils::Config));
210         item->setCheckState(0, Qt::Checked);
211         item->setData(0, action, type);
212         break;
213     }
214     case Utils::Data: {
215         auto item = new QTreeWidgetItem(parent);
216         item->setText(0, Utils::storedTypeToI18n(Utils::Data));
217         item->setCheckState(0, Qt::Checked);
218         item->setData(0, action, type);
219         break;
220     }
221     }
222 }
223 
selectAllItems()224 void SelectionTypeTreeWidget::selectAllItems()
225 {
226     setSelectItems(true);
227 }
228 
unSelectAllItems()229 void SelectionTypeTreeWidget::unSelectAllItems()
230 {
231     setSelectItems(false);
232 }
233 
setSelectItems(bool b)234 void SelectionTypeTreeWidget::setSelectItems(bool b)
235 {
236     changeState(mKmailItem, b);
237     changeState(mKalarmItem, b);
238     changeState(mKaddressbookItem, b);
239     changeState(mKorganizerItem, b);
240     changeState(mKNotesItem, b);
241     changeState(mAkregatorItem, b);
242 }
243 
changeState(QTreeWidgetItem * item,bool b)244 void SelectionTypeTreeWidget::changeState(QTreeWidgetItem *item, bool b)
245 {
246     if (item) {
247         blockSignals(true);
248         item->setCheckState(0, b ? Qt::Checked : Qt::Unchecked);
249         for (int i = 0; i < item->childCount(); ++i) {
250             item->child(i)->setCheckState(0, b ? Qt::Checked : Qt::Unchecked);
251         }
252         blockSignals(false);
253     }
254 }
255 
slotItemChanged(QTreeWidgetItem * item,int column)256 void SelectionTypeTreeWidget::slotItemChanged(QTreeWidgetItem *item, int column)
257 {
258     if (column != 0) {
259         return;
260     }
261     // Parent
262     if (item->childCount() != 0) {
263         changeState(item, item->checkState(0) == Qt::Checked);
264     } else { // child
265         blockSignals(true);
266         QTreeWidgetItem *parent = item->parent();
267         Qt::CheckState state = Qt::PartiallyChecked;
268         for (int i = 0; i < parent->childCount(); ++i) {
269             if (i == 0) {
270                 state = parent->child(i)->checkState(0);
271             } else {
272                 if (state != parent->child(i)->checkState(0)) {
273                     state = Qt::PartiallyChecked;
274                     break;
275                 }
276             }
277         }
278         parent->setCheckState(0, state);
279         blockSignals(false);
280     }
281 }
282 
loadFileName(const QString & fileName)283 void SelectionTypeTreeWidget::loadFileName(const QString &fileName)
284 {
285     unSelectAllItems();
286     TemplateSelection templateSelection;
287     const QHash<Utils::AppsType, Utils::importExportParameters> params = templateSelection.loadTemplate(fileName);
288     setParameters(params);
289 }
290 
loadDefaultTemplate()291 void SelectionTypeTreeWidget::loadDefaultTemplate()
292 {
293     // Keep old name for compatibility
294     QString ret = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("/pimsettingexporter/defaulttemplate.xml"));
295     if (ret.isEmpty()) {
296         ret = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("/pimdataexporter/defaulttemplate.xml"));
297     }
298     if (!ret.isEmpty()) {
299         loadFileName(ret);
300     }
301 }
302 
loadTemplate(const QString & fileName)303 void SelectionTypeTreeWidget::loadTemplate(const QString &fileName)
304 {
305     if (fileName.isEmpty()) {
306         QPointer<QFileDialog> dlg = new QFileDialog(this, QString(), QString(), QStringLiteral("*.xml"));
307         dlg->setFileMode(QFileDialog::ExistingFile);
308         if (dlg->exec()) {
309             const QStringList file = dlg->selectedFiles();
310             loadFileName(file.at(0));
311         }
312         delete dlg;
313     } else {
314         loadFileName(fileName);
315     }
316 }
317 
exportedFileInfo()318 QString SelectionTypeTreeWidget::exportedFileInfo()
319 {
320     const QString templateStr = templateSelectionToString();
321     QTemporaryFile tmp;
322     tmp.open();
323     tmp.setAutoRemove(false);
324     PimCommon::Util::saveToFile(tmp.fileName(), templateStr);
325     return tmp.fileName();
326 }
327 
templateSelectionToString()328 QString SelectionTypeTreeWidget::templateSelectionToString()
329 {
330     TemplateSelection templateSelection;
331     templateSelection.createTemplate(storedType());
332     const QString templateStr = templateSelection.saveTemplate();
333     return templateStr;
334 }
335 
saveAsDefaultTemplate()336 void SelectionTypeTreeWidget::saveAsDefaultTemplate()
337 {
338     const QString templateStr = templateSelectionToString();
339     QString ret = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/pimdataexporter/");
340     QDir().mkpath(ret);
341 
342     PimCommon::Util::saveToFile(ret + QStringLiteral("defaulttemplate.xml"), templateStr);
343 }
344 
saveAsTemplate()345 void SelectionTypeTreeWidget::saveAsTemplate()
346 {
347     const QString templateStr = templateSelectionToString();
348     const QString filter(i18n("Template Files (*.xml)"));
349     PimCommon::Util::saveTextAs(templateStr, filter, this);
350 }
351 
initializeSubItem(QTreeWidgetItem * item,Utils::StoredTypes types)352 void SelectionTypeTreeWidget::initializeSubItem(QTreeWidgetItem *item, Utils::StoredTypes types)
353 {
354     for (int i = 0; i < item->childCount(); ++i) {
355         QTreeWidgetItem *child = item->child(i);
356         if (types & static_cast<Utils::StoredType>(child->data(0, action).toInt())) {
357             child->setCheckState(0, Qt::Checked);
358         } else {
359             child->setCheckState(0, Qt::Unchecked);
360         }
361     }
362 }
363 
setParameters(const QHash<Utils::AppsType,Utils::importExportParameters> & params)364 void SelectionTypeTreeWidget::setParameters(const QHash<Utils::AppsType, Utils::importExportParameters> &params)
365 {
366     QHash<Utils::AppsType, Utils::importExportParameters>::const_iterator i = params.constBegin();
367     while (i != params.constEnd()) {
368         switch (i.key()) {
369         case Utils::KMail:
370             initializeSubItem(mKmailItem, i.value().types);
371             break;
372         case Utils::KAddressBook:
373             initializeSubItem(mKaddressbookItem, i.value().types);
374             break;
375         case Utils::KAlarm:
376             initializeSubItem(mKalarmItem, i.value().types);
377             break;
378         case Utils::KOrganizer:
379             initializeSubItem(mKorganizerItem, i.value().types);
380             break;
381         case Utils::KNotes:
382             initializeSubItem(mKNotesItem, i.value().types);
383             break;
384         case Utils::Akregator:
385             initializeSubItem(mAkregatorItem, i.value().types);
386             break;
387         case Utils::Unknown:
388             break;
389         }
390         ++i;
391     }
392 }
393