Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include "treeviewmodel.hpp"
10 :
11 : #include <backends.hpp>
12 : #include <kdbconfig.h> // for DEBUG and VERBOSE
13 : #include <kdbease.h>
14 : #include <kdbproposal.h> // for namespaces
15 : #include <modules.hpp>
16 : #include <plugin.hpp>
17 : #include <plugins.hpp>
18 : #include <toolexcept.hpp>
19 :
20 : #if HAVE_DBUS
21 : #include <QtDBus/QtDBus>
22 : #endif
23 :
24 : #include "kdblogger.h"
25 : #include <merging/automergeconfiguration.hpp>
26 : #include <merging/automergestrategy.hpp>
27 : #include <merging/mergeconflictstrategy.hpp>
28 : #include <merging/onesidestrategy.hpp>
29 : #include <merging/onesidevaluestrategy.hpp>
30 : #include <merging/threewaymerge.hpp>
31 :
32 : using namespace std;
33 : using namespace kdb;
34 : using namespace kdb::tools;
35 : using namespace kdb::tools::merging;
36 :
37 0 : TreeViewModel::TreeViewModel (QObject * parentModel) : m_root ("/", KEY_END), m_kdb ()
38 : {
39 : Q_UNUSED (parentModel);
40 0 : }
41 :
42 0 : TreeViewModel::TreeViewModel (MergingKDB * kdb, QObject * parentModel) : m_root ("/", KEY_END), m_kdb (kdb)
43 : {
44 : Q_UNUSED (parentModel);
45 0 : connectDBus ();
46 0 : }
47 :
48 0 : TreeViewModel::TreeViewModel (const TreeViewModel & other)
49 0 : : QAbstractListModel (), m_model (other.m_model), m_root (other.m_root), m_kdb (other.m_kdb)
50 :
51 : {
52 0 : }
53 :
54 0 : int TreeViewModel::rowCount (const QModelIndex & parentIndex) const
55 : {
56 : Q_UNUSED (parentIndex);
57 0 : return m_model.count ();
58 : }
59 :
60 0 : QVariant TreeViewModel::data (const QModelIndex & idx, int role) const
61 : {
62 0 : if (!idx.isValid ())
63 : {
64 0 : emit showMessage (tr ("Error"), tr ("Index not valid."),
65 0 : QString ("TreeViewModel::data: Index = %1,\nModel size = %2").arg (idx.row ()).arg (m_model.count ()));
66 : return QVariant ();
67 : }
68 :
69 0 : if (idx.row () > (m_model.size () - 1))
70 : {
71 0 : emit showMessage (tr ("Error"), QString (tr ("Index too high. ")),
72 0 : QString ("TreeViewModel::data: Index: %1").arg (idx.row ()));
73 : return QVariant ();
74 : }
75 :
76 0 : ConfigNode * node = m_model.at (idx.row ()).data ();
77 :
78 0 : switch (role)
79 : {
80 :
81 : case Qt::DisplayRole:
82 :
83 : // TODO: document fallthrough if it was desired
84 : case NameRole:
85 0 : return QVariant::fromValue (node->getName ());
86 :
87 : case PathRole:
88 0 : return QVariant::fromValue (node->getPath ());
89 :
90 : case ValueRole:
91 0 : return QVariant::fromValue (node->getValue ());
92 :
93 : case ChildCountRole:
94 0 : return QVariant::fromValue (node->getChildCount ());
95 :
96 : case ChildrenRole:
97 0 : return QVariant::fromValue (node->getChildren ());
98 :
99 : case ChildrenHaveNoChildrenRole:
100 0 : return QVariant::fromValue (node->childrenHaveNoChildren ());
101 :
102 : case MetaValueRole:
103 0 : return QVariant::fromValue (node->getMetaKeys ());
104 :
105 : case NodeRole:
106 : return QVariant::fromValue (node);
107 :
108 : case ParentModelRole:
109 0 : return QVariant::fromValue (node->getParentModel ());
110 :
111 : case IndexRole:
112 0 : return QVariant::fromValue (idx.row ());
113 :
114 : case IsNullRole:
115 : {
116 0 : if (node->getKey ())
117 0 : return QVariant::fromValue (false);
118 : else
119 0 : return QVariant::fromValue (true);
120 : }
121 :
122 : case IsExpandedRole:
123 0 : return QVariant::fromValue (node->isExpanded ());
124 :
125 : default:
126 0 : emit showMessage (tr ("Error"), tr ("Unknown role: %1").arg (role), "TreeViewModel::data");
127 : return QVariant ();
128 : }
129 : }
130 :
131 0 : bool TreeViewModel::setData (const QModelIndex & idx, const QVariant & modelData, int role)
132 : {
133 0 : if (!idx.isValid () || idx.row () > (m_model.size () - 1))
134 : {
135 0 : emit showMessage (tr ("Error"), tr ("Index not valid."),
136 0 : QString ("TreeViewModel::setData: Index = %1,\nModel size = %2").arg (idx.row ()).arg (m_model.count ()));
137 0 : return false;
138 : }
139 :
140 0 : ConfigNodePtr node = m_model.at (idx.row ());
141 :
142 0 : switch (role)
143 : {
144 :
145 : case NameRole:
146 0 : if (node->getName () != modelData.toString ())
147 : {
148 0 : node->setName (modelData.toString ());
149 0 : node->setIsDirty (true);
150 : }
151 : break;
152 :
153 : case ValueRole:
154 0 : if (node->getValue () != modelData)
155 : {
156 0 : node->setValue (modelData);
157 : }
158 : break;
159 :
160 : case MetaValueRole:
161 : {
162 0 : QVariantList valueList = modelData.toList ();
163 0 : node->setMeta (valueList.at (0).toString (), valueList.at (1));
164 : break;
165 : }
166 :
167 : case IsExpandedRole:
168 0 : node->setIsExpanded (modelData.toBool ());
169 : }
170 :
171 0 : emit dataChanged (idx, idx);
172 :
173 0 : return true;
174 : }
175 :
176 0 : int TreeViewModel::getIndexByName (const QString & name) const
177 : {
178 0 : for (int i = 0; i < m_model.count (); i++)
179 : {
180 0 : if (m_model.at (i)->getName () == name) return i;
181 : }
182 :
183 : return -1;
184 : }
185 :
186 0 : void TreeViewModel::importConfiguration (const QString & name, const QString & format, QString & file, const QVariantList & mergeStrategies)
187 : {
188 0 : Key root (name.toStdString (), KEY_END);
189 0 : KeySet originalKeys = collectCurrentKeySet ();
190 0 : KeySet base = originalKeys.cut (root);
191 0 : printWarnings (cerr, root, true, true);
192 :
193 0 : KeySet importedKeys;
194 :
195 0 : string formatString = format.toStdString ();
196 0 : string fileString = file.remove ("file://").toStdString ();
197 :
198 0 : Modules modules;
199 0 : PluginPtr plugin = modules.load (formatString);
200 :
201 0 : Key errorKey (root);
202 0 : errorKey.setString (fileString);
203 :
204 0 : plugin->get (importedKeys, errorKey);
205 :
206 0 : stringstream ws;
207 0 : stringstream es;
208 0 : QString warnings;
209 0 : QString errors;
210 :
211 0 : printWarnings (ws, errorKey, true, true);
212 0 : warnings = QString::fromStdString (ws.str ());
213 0 : printError (es, errorKey, true, true);
214 0 : errors = QString::fromStdString (es.str ());
215 :
216 0 : if (!errors.isEmpty ())
217 : {
218 0 : emit showMessage (tr ("Error"),
219 0 : tr ("Failed to import configuration from %1 to %2.").arg (file, QString::fromStdString (root.getName ())),
220 0 : errors);
221 0 : return;
222 : }
223 :
224 0 : ThreeWayMerge merger;
225 :
226 0 : foreach (QVariant s, mergeStrategies)
227 : {
228 0 : MergeConflictStrategy * strategy = getMergeStrategy (s.toString ());
229 :
230 0 : if (strategy) merger.addConflictStrategy (strategy);
231 : }
232 :
233 0 : MergeResult result;
234 :
235 : try
236 : {
237 0 : result = merger.mergeKeySet (
238 0 : MergeTask (BaseMergeKeys (base, root), OurMergeKeys (base, root), TheirMergeKeys (importedKeys, root), root));
239 : }
240 0 : catch (...) // TODO: Which exceptions are possible?
241 : {
242 0 : emit showMessage (tr ("Error"), tr ("Could not merge keys."), "");
243 : }
244 :
245 0 : if (!result.hasConflicts ())
246 : {
247 0 : createNewNodes (result.getMergedKeys ());
248 :
249 0 : if (importedKeys.size () > 0)
250 0 : emit showMessage (tr ("Information"), tr ("Successfully imported %1 keys.").arg (importedKeys.size ()), "");
251 : }
252 : else
253 : {
254 0 : KeySet conflictSet = result.getConflictSet ();
255 0 : QStringList conflicts;
256 0 : conflictSet.rewind ();
257 0 : Key current;
258 :
259 0 : while ((current = conflictSet.next ()))
260 : {
261 0 : QString ourConflict = QString::fromStdString (current.getMeta<string> ("conflict/operation/our"));
262 0 : QString theirConflict = QString::fromStdString (current.getMeta<string> ("conflict/operation/their"));
263 :
264 0 : conflicts.append (QString::fromStdString (current.getName ()));
265 0 : conflicts.append ("Ours: " + ourConflict + ", Theirs " + theirConflict);
266 0 : conflicts.append ("\n");
267 : }
268 :
269 : emit showMessage (
270 0 : tr ("Error"),
271 0 : tr ("The were conflicts importing %1 (%2 format) into %3, no configuration was imported.").arg (file, format, name),
272 0 : conflicts.join ("\n"));
273 : }
274 : }
275 :
276 0 : void TreeViewModel::exportConfiguration (TreeViewModel * parentModel, int idx, QString format, QString file)
277 : {
278 0 : KeySet ks = collectCurrentKeySet ();
279 0 : Key root = parentModel->model ().at (idx)->getKey ();
280 :
281 : // Node is only a filler
282 0 : if (!root) root = Key (parentModel->model ().at (idx)->getPath ().toStdString (), KEY_END);
283 :
284 0 : KeySet part (ks.cut (root));
285 :
286 0 : string formatString = format.toStdString ();
287 0 : string fileString = file.remove ("file://").toStdString ();
288 :
289 0 : Modules modules;
290 0 : PluginPtr plugin = modules.load (formatString);
291 :
292 0 : Key errorKey (root);
293 0 : errorKey.setString (fileString);
294 :
295 0 : plugin->set (part, errorKey);
296 :
297 0 : stringstream ws;
298 0 : stringstream es;
299 0 : QString warnings;
300 0 : QString errors;
301 :
302 0 : printWarnings (ws, errorKey, true, true);
303 0 : warnings = QString::fromStdString (ws.str ());
304 0 : printError (es, errorKey, true, true);
305 0 : errors = QString::fromStdString (es.str ());
306 :
307 0 : if (errors.isEmpty () && !warnings.isEmpty ())
308 0 : emit showMessage (tr ("Information"),
309 0 : tr ("Successfully exported configuration below %1 to %2, warnings were issued.")
310 0 : .arg (QString::fromStdString (root.getName ()), file),
311 0 : "");
312 0 : else if (!errors.isEmpty () && warnings.isEmpty ())
313 0 : emit showMessage (
314 0 : tr ("Error"),
315 0 : tr ("Failed to export configuration below %1 to %2.").arg (QString::fromStdString (root.getName ()), file), errors);
316 0 : else if (!errors.isEmpty () && !warnings.isEmpty ())
317 : emit showMessage (
318 0 : tr ("Error"),
319 0 : tr ("Failed to export configuration below %1 to %2.").arg (QString::fromStdString (root.getName ()), file),
320 0 : warnings + "\n" + errors);
321 0 : }
322 :
323 0 : KeySet TreeViewModel::collectCurrentKeySet ()
324 : {
325 0 : KeySetVisitor ksVisit;
326 0 : accept (ksVisit);
327 :
328 0 : return ksVisit.getKeySet ();
329 : }
330 :
331 0 : Qt::ItemFlags TreeViewModel::flags (const QModelIndex & idx) const
332 : {
333 0 : if (!idx.isValid ()) return Qt::ItemIsEnabled;
334 :
335 0 : return QAbstractItemModel::flags (idx) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
336 : }
337 :
338 0 : void TreeViewModel::accept (Visitor & visitor)
339 : {
340 0 : visitor.visit (this);
341 0 : }
342 :
343 0 : QVariantMap TreeViewModel::get (const int & idx) const
344 : {
345 0 : QVariantMap map;
346 :
347 0 : foreach (int k, roleNames ().keys ())
348 : {
349 0 : map[roleNames ().value (k)] = data (index (idx, 0), k);
350 : }
351 :
352 0 : return map;
353 : }
354 :
355 0 : QVariant TreeViewModel::find (const QString & term)
356 : {
357 0 : auto searchResults = new TreeViewModel;
358 0 : FindVisitor fVisit (searchResults, term);
359 0 : accept (fVisit);
360 :
361 0 : if (searchResults->rowCount () == 0)
362 : {
363 0 : searchResults->model ().append (
364 0 : ConfigNodePtr (new ConfigNode ("NotfoundNode", tr ("There were no results matching your query."), nullptr, this)));
365 : }
366 :
367 0 : QQmlEngine::setObjectOwnership (searchResults, QQmlApplicationEngine::CppOwnership);
368 :
369 0 : return QVariant::fromValue (searchResults);
370 : }
371 :
372 0 : bool TreeViewModel::removeRow (int row, const QModelIndex & parentIndex)
373 : {
374 : Q_UNUSED (parentIndex);
375 :
376 0 : if (row < 0 || row > m_model.size () - 1)
377 : {
378 0 : emit showMessage (tr ("Error"), tr ("Index not valid."),
379 0 : QString ("TreeViewModel::removeRow: Index = %1, Model size = %2").arg (m_model.size ()).arg (row));
380 0 : return false;
381 : }
382 :
383 0 : beginRemoveRows (QModelIndex (), row, row);
384 :
385 0 : if (!m_model.isEmpty ()) m_model.removeAt (row);
386 :
387 0 : endRemoveRows ();
388 :
389 0 : int childCount = 0;
390 :
391 0 : foreach (ConfigNodePtr node, m_model)
392 : {
393 0 : childCount += node->getChildCount ();
394 : }
395 :
396 0 : if (childCount == 0) emit expandNode (false);
397 :
398 0 : emit updateIndicator ();
399 :
400 0 : return true;
401 : }
402 :
403 0 : bool TreeViewModel::insertRow (int row, const QModelIndex & parentIndex)
404 : {
405 : Q_UNUSED (parentIndex);
406 0 : ConfigNodePtr node (new ConfigNode);
407 0 : node->setName (QString::fromStdString (m_metaModelParent.getName ()));
408 0 : node->setKey (m_metaModelParent);
409 0 : node->setParentModel (this);
410 :
411 0 : beginInsertRows (QModelIndex (), row, row);
412 0 : m_model.insert (row, node);
413 0 : endInsertRows ();
414 :
415 0 : emit updateIndicator ();
416 :
417 0 : return true;
418 : }
419 :
420 0 : void TreeViewModel::insertRow (int row, ConfigNodePtr node, bool addParent)
421 : {
422 0 : beginInsertRows (QModelIndex (), row, row);
423 0 : if (addParent) node->setParentModel (this);
424 0 : m_model.insert (row, node);
425 0 : endInsertRows ();
426 :
427 0 : emit updateIndicator ();
428 0 : }
429 :
430 0 : void TreeViewModel::insertMetaRow (int row, Key key, const QString & name)
431 : {
432 0 : m_metaModelParent = key;
433 :
434 0 : if (m_metaModelParent)
435 : {
436 0 : insertRow (row);
437 : }
438 : else
439 : {
440 0 : QString keyName;
441 :
442 0 : if (key)
443 0 : keyName = QString::fromStdString (key.getFullName ());
444 : else
445 0 : keyName = name;
446 :
447 0 : emit showMessage (tr ("Error"), tr ("Inserting of Metakey failed, \"%1\" is not valid.").arg (keyName), "");
448 : }
449 0 : }
450 :
451 0 : void TreeViewModel::sink (ConfigNodePtr node, QStringList keys, const Key & key)
452 : {
453 0 : if (keys.length () == 0) return;
454 :
455 0 : bool isLeaf = (keys.length () == 1);
456 :
457 0 : QString name = keys.takeFirst ();
458 :
459 0 : if (node->hasChild (name) && !node->getChildByName (name)->isDirty ())
460 : {
461 0 : if (node->getChildByName (name)->getKey () && node->getChildByName (name)->getKey ().getName () == key.getName ())
462 : {
463 0 : if (node->getChildByName (name)->getKey ().getName () == key.getName ())
464 : {
465 0 : node->getChildByName (name)->updateNode (key);
466 : }
467 : }
468 :
469 0 : sink (node->getChildByName (name), keys, key);
470 : }
471 : else
472 : {
473 0 : if (node->hasChild (name)) node->getChildren ()->removeRow (node->getChildIndexByName (name));
474 :
475 0 : ConfigNodePtr newNode;
476 :
477 0 : if (isLeaf)
478 0 : newNode = ConfigNodePtr (new ConfigNode (name, (node->getPath () + "/" + name), key, node->getChildren ()));
479 : else
480 0 : newNode = ConfigNodePtr (new ConfigNode (name, (node->getPath () + "/" + name), nullptr, node->getChildren ()));
481 :
482 0 : node->appendChild (newNode);
483 :
484 0 : sink (newNode, keys, key);
485 : }
486 : }
487 :
488 0 : void TreeViewModel::populateModel ()
489 : {
490 0 : kdb::KeySet config;
491 0 : m_kdb->get (config, m_root);
492 0 : populateModel (config);
493 0 : }
494 :
495 0 : void TreeViewModel::populateModel (KeySet const & keySet)
496 : {
497 0 : m_model.clear ();
498 :
499 : using namespace ckdb; // for namespaces
500 0 : for (int i = KEY_NS_FIRST; i <= KEY_NS_LAST; ++i)
501 : {
502 0 : elektraNamespace ns = static_cast<elektraNamespace> (i);
503 0 : ConfigNodePtr toAdd;
504 0 : switch (ns)
505 : {
506 : case KEY_NS_SPEC:
507 0 : toAdd = ConfigNodePtr (new ConfigNode ("spec", "spec", nullptr, this));
508 0 : break;
509 : case KEY_NS_PROC:
510 : // TODO: add generic commandline parsing
511 : break;
512 : case KEY_NS_DIR:
513 0 : toAdd = ConfigNodePtr (new ConfigNode ("dir", "dir", nullptr, this));
514 0 : break;
515 : case KEY_NS_USER:
516 0 : toAdd = ConfigNodePtr (new ConfigNode ("user", "user", nullptr, this));
517 0 : break;
518 : case KEY_NS_SYSTEM:
519 0 : toAdd = ConfigNodePtr (new ConfigNode ("system", "system", nullptr, this));
520 0 : break;
521 : case KEY_NS_EMPTY:
522 : break;
523 : case KEY_NS_NONE:
524 : break;
525 : case KEY_NS_META:
526 : break;
527 : case KEY_NS_CASCADING:
528 : break;
529 : }
530 0 : if (toAdd) m_model << toAdd;
531 : }
532 :
533 0 : createNewNodes (keySet);
534 0 : }
535 :
536 0 : void TreeViewModel::createNewNodes (KeySet keySet)
537 : {
538 : keySet.rewind ();
539 :
540 0 : while (keySet.next ())
541 : {
542 0 : Key k = keySet.current ();
543 0 : QStringList keys = getSplittedKeyname (k);
544 0 : QString root = keys.takeFirst ();
545 :
546 0 : for (int i = 0; i < m_model.count (); i++)
547 : {
548 0 : if (root == m_model.at (i)->getName ()) sink (m_model.at (i), keys, k);
549 : }
550 : }
551 0 : }
552 :
553 0 : Key TreeViewModel::createNewKey (const QString & path, const QString & value, const QVariantMap metaData)
554 : {
555 0 : Key key;
556 0 : key.setName (path.toStdString ());
557 0 : key.setString (value.toStdString ());
558 :
559 0 : for (QVariantMap::const_iterator iter = metaData.begin (); iter != metaData.end (); iter++)
560 : {
561 0 : key.setMeta (iter.key ().toStdString (), iter.value ().toString ().toStdString ());
562 : }
563 :
564 0 : return key;
565 : }
566 :
567 0 : void TreeViewModel::append (ConfigNodePtr node)
568 : {
569 0 : insertRow (rowCount (), node);
570 0 : }
571 :
572 : namespace
573 : {
574 :
575 : #if DEBUG && VERBOSE
576 : std::string printKey (Key const & k)
577 : {
578 : std::string ret;
579 : ret += k.getName ();
580 :
581 : if (ckdb::keyNeedSync (*k)) ret += "°";
582 :
583 : if (!k.isBinary ())
584 : {
585 : ret += "=";
586 : ret += k.getString ();
587 : }
588 : return ret;
589 : }
590 :
591 : void printKeys (KeySet const & theirs, KeySet const & base, KeySet const & ours)
592 : {
593 : theirs.rewind ();
594 : base.rewind ();
595 : for (Key o : ours)
596 : {
597 : std::string prefix ("user/guitest");
598 : Key t = theirs.next ();
599 : Key b = base.next ();
600 : if (!((o && !o.getName ().compare (0, prefix.size (), prefix)) &&
601 : (t && !t.getName ().compare (0, prefix.size (), prefix)) && (b && !b.getName ().compare (0, prefix.size (), prefix))))
602 : continue;
603 : std::cout << printKey (o);
604 : ;
605 : std::cout << "\t";
606 : !b.isValid () ? std::cout << "none" : std::cout << printKey (b);
607 : std::cout << "\t";
608 : !t.isValid () ? std::cout << "none" : std::cout << printKey (t);
609 : std::cout << std::endl;
610 : }
611 : }
612 : #endif
613 : } // namespace
614 :
615 0 : QStringList getConflicts (KeySet const & conflictSet)
616 : {
617 0 : QStringList conflicts;
618 0 : conflictSet.rewind ();
619 0 : Key current;
620 :
621 0 : while ((current = conflictSet.next ()))
622 : {
623 0 : QString ourConflict = QString::fromStdString (current.getMeta<string> ("conflict/operation/our"));
624 0 : QString theirConflict = QString::fromStdString (current.getMeta<string> ("conflict/operation/their"));
625 :
626 0 : conflicts.append (QString::fromStdString (current.getName ()));
627 0 : conflicts.append ("Ours: " + ourConflict + ", Theirs " + theirConflict);
628 0 : conflicts.append ("\n");
629 : }
630 0 : return conflicts;
631 : }
632 :
633 0 : void TreeViewModel::synchronize ()
634 : {
635 0 : KeySet ours = collectCurrentKeySet ();
636 :
637 : try
638 : {
639 : #if DEBUG && VERBOSE
640 : std::cout << "guitest: start" << std::endl;
641 : printKeys (ours, ours, ours);
642 : #endif
643 :
644 0 : ThreeWayMerge merger;
645 0 : AutoMergeConfiguration configuration;
646 0 : configuration.configureMerger (merger);
647 :
648 : // write our config
649 0 : m_kdb->synchronize (ours, m_root, merger);
650 :
651 : #if DEBUG && VERBOSE
652 : std::cout << "guitest: after get" << std::endl;
653 : printKeys (ours, ours, ours);
654 : #endif
655 :
656 0 : createNewNodes (ours);
657 : }
658 0 : catch (MergingKDBException const & exc)
659 : {
660 0 : QStringList conflicts = getConflicts (exc.getConflicts ());
661 0 : emit showMessage (tr ("Error"), tr ("Synchronizing failed, conflicts occurred."), conflicts.join ("\n"));
662 : }
663 0 : catch (KDBException const & e)
664 : {
665 0 : QMap<QString, QString> message = getErrorMessage (e);
666 :
667 : emit showMessage (
668 0 : tr ("Error"), message.value ("error"),
669 0 : QString ("%1%2%3").arg (message.value ("at"), message.value ("mountpoint"), message.value ("configfile")));
670 : }
671 0 : }
672 :
673 0 : QMap<QString, QString> TreeViewModel::getErrorMessage (KDBException const & e)
674 : {
675 0 : QRegExp error_regex ("Sorry, ((.*\\n){2})");
676 0 : QRegExp at_regex ("At: (.*)\\n");
677 0 : QRegExp mountpoint_regex ("Mountpoint: (.*)\\n");
678 0 : QRegExp configfile_regex ("Configfile: (.*)\\n");
679 :
680 0 : QMap<QString, QString> message;
681 0 : QString error = QString (e.what ());
682 :
683 0 : error_regex.setMinimal (true);
684 0 : at_regex.setMinimal (true);
685 0 : mountpoint_regex.setMinimal (true);
686 0 : configfile_regex.setMinimal (true);
687 :
688 0 : error_regex.indexIn (error);
689 0 : at_regex.indexIn (error);
690 0 : mountpoint_regex.indexIn (error);
691 0 : configfile_regex.indexIn (error);
692 :
693 0 : message.insert ("error", error_regex.cap ());
694 0 : message.insert ("at", at_regex.cap ());
695 0 : message.insert ("mountpoint", mountpoint_regex.cap ());
696 0 : message.insert ("configfile", configfile_regex.cap ());
697 :
698 :
699 0 : return message;
700 : }
701 :
702 0 : void TreeViewModel::clearMetaModel ()
703 : {
704 0 : beginResetModel ();
705 0 : m_model.clear ();
706 0 : endResetModel ();
707 0 : }
708 :
709 0 : void TreeViewModel::unMountBackend (QString backendName)
710 : {
711 0 : KeySet keySet = collectCurrentKeySet ();
712 0 : Backends::umount (backendName.toStdString (), keySet);
713 0 : populateModel (keySet);
714 0 : synchronize ();
715 0 : }
716 :
717 0 : void TreeViewModel::refresh ()
718 : {
719 0 : layoutAboutToBeChanged ();
720 0 : layoutChanged ();
721 :
722 0 : emit updateIndicator ();
723 0 : }
724 :
725 0 : QString TreeViewModel::getCurrentArrayNo () const
726 : {
727 0 : ConfigNodePtr max (nullptr);
728 :
729 0 : foreach (ConfigNodePtr node, m_model)
730 : {
731 0 : if (node->getName ().startsWith ("#"))
732 : {
733 0 : max = node;
734 : }
735 : }
736 :
737 0 : if (max)
738 : {
739 0 : Key k = max->getKey ();
740 0 : ckdb::elektraArrayIncName (k.getKey ());
741 0 : return QString::fromStdString (k.getBaseName ());
742 : }
743 :
744 0 : return "#0";
745 : }
746 :
747 0 : void TreeViewModel::refreshArrayNumbers ()
748 : {
749 0 : QList<ConfigNodePtr> arrayElements;
750 :
751 0 : foreach (ConfigNodePtr node, m_model)
752 : {
753 0 : if (node->getName ().startsWith ("#"))
754 : {
755 0 : arrayElements.append (node);
756 : }
757 : }
758 :
759 0 : if (!arrayElements.isEmpty ())
760 : {
761 :
762 0 : arrayElements.at (0)->setName ("#0");
763 :
764 0 : if (arrayElements.count () > 1)
765 : {
766 :
767 0 : for (int i = 1; i < arrayElements.count (); i++)
768 : {
769 0 : Key k = arrayElements.at (i - 1)->getKey ().dup ();
770 0 : ckdb::elektraArrayIncName (k.getKey ());
771 0 : arrayElements.at (i)->setName (QString::fromStdString (k.getBaseName ()));
772 : }
773 : }
774 : }
775 0 : }
776 :
777 0 : QStringList TreeViewModel::mountedBackends ()
778 : {
779 0 : KeySet keySet = collectCurrentKeySet ();
780 :
781 0 : Backends::BackendInfoVector mtab = Backends::getBackendInfo (keySet);
782 :
783 0 : QStringList mountedBends;
784 :
785 0 : for (Backends::BackendInfoVector::const_iterator it = mtab.begin (); it != mtab.end (); ++it)
786 : {
787 0 : mountedBends.append (QString::fromStdString (it->name));
788 : }
789 :
790 : // cannot read the size of the QStringList in QML
791 0 : if (mountedBends.isEmpty ()) mountedBends.append ("empty");
792 :
793 0 : return mountedBends;
794 : }
795 :
796 0 : QStringList TreeViewModel::getSplittedKeyname (const Key & key)
797 : {
798 0 : QStringList names;
799 :
800 0 : for (auto && elem : key)
801 : {
802 0 : names.append (QString::fromStdString (elem));
803 : }
804 :
805 0 : return names;
806 : }
807 :
808 0 : void TreeViewModel::discardModel ()
809 : {
810 0 : delete this;
811 0 : }
812 :
813 0 : MergeConflictStrategy * TreeViewModel::getMergeStrategy (const QString & mergeStrategy)
814 : {
815 0 : if (mergeStrategy == "Preserve")
816 0 : return new AutoMergeStrategy ();
817 0 : else if (mergeStrategy == "Ours")
818 0 : return new OneSideStrategy (OURS);
819 0 : else if (mergeStrategy == "Theirs")
820 0 : return new OneSideStrategy (THEIRS);
821 0 : else if (mergeStrategy == "Base")
822 0 : return new OneSideStrategy (BASE);
823 0 : else if (mergeStrategy == "None")
824 : return nullptr;
825 :
826 : return nullptr;
827 : }
828 :
829 0 : void TreeViewModel::showConfigNodeMessage (QString title, QString text, QString detailedText)
830 : {
831 0 : emit showMessage (title, text, detailedText);
832 0 : }
833 :
834 0 : void TreeViewModel::connectDBus ()
835 : {
836 : #if HAVE_DBUS
837 0 : if (QDBusConnection::sessionBus ().connect (QString (), "/org/libelektra/configuration", "org.libelektra", QString (), this,
838 : SLOT (configChanged (QString))))
839 : {
840 : ELEKTRA_LOG ("Successfully connected to DBus");
841 : }
842 : else
843 : {
844 : ELEKTRA_LOG ("Failed to connect to DBus");
845 : }
846 : #else
847 : ELEKTRA_LOG ("No DBus support");
848 : #endif
849 0 : }
850 :
851 0 : void TreeViewModel::configChanged (QString msg)
852 : {
853 : Q_UNUSED (msg)
854 : ELEKTRA_LOG ("config changed: %s", msg.toLocal8Bit ().data ());
855 :
856 0 : synchronize ();
857 0 : refresh ();
858 0 : }
859 :
860 0 : QHash<int, QByteArray> TreeViewModel::roleNames () const
861 : {
862 0 : QHash<int, QByteArray> roles;
863 :
864 0 : roles[NameRole] = "name";
865 0 : roles[PathRole] = "path";
866 0 : roles[ValueRole] = "value";
867 0 : roles[ChildCountRole] = "childCount";
868 0 : roles[ChildrenRole] = "children";
869 0 : roles[ChildrenHaveNoChildrenRole] = "childrenHaveNoChildren";
870 0 : roles[MetaValueRole] = "metaValue";
871 0 : roles[NodeRole] = "node";
872 0 : roles[ParentModelRole] = "parentModel";
873 0 : roles[IndexRole] = "index";
874 0 : roles[IsNullRole] = "isNull";
875 0 : roles[IsExpandedRole] = "isExpanded";
876 :
877 0 : return roles;
878 0 : }
|