24 changed files with 1286 additions and 50 deletions
			
			
		@ -0,0 +1,244 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
 | 
					<!DOCTYPE TS> | 
				
			||||
 | 
					<TS version="2.1" language="de_DE"> | 
				
			||||
 | 
					<context> | 
				
			||||
 | 
					    <name>DrawerViewModel</name> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location filename="drawerviewmodel.cpp" line="+11"/> | 
				
			||||
 | 
					        <source>Main Sample</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Tab Sample</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Settings</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					</context> | 
				
			||||
 | 
					<context> | 
				
			||||
 | 
					    <name>SampleViewModel</name> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location filename="sampleviewmodel.cpp" line="+81"/> | 
				
			||||
 | 
					        <source>Random input</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Enter a number:</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+12"/> | 
				
			||||
 | 
					        <source>Open Files:</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+12"/> | 
				
			||||
 | 
					        <source>Clear Eventlist</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Do you really want to clear the eventlist?</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+9"/> | 
				
			||||
 | 
					        <source>QtMvvm sample application</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+2"/> | 
				
			||||
 | 
					        <source>BSD 3 Clause</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					</context> | 
				
			||||
 | 
					<context> | 
				
			||||
 | 
					    <name>TabItemViewModel</name> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location filename="tabviewmodel.cpp" line="+28"/> | 
				
			||||
 | 
					        <source>No Title</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					</context> | 
				
			||||
 | 
					<context> | 
				
			||||
 | 
					    <name>TabViewModel</name> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="-13"/> | 
				
			||||
 | 
					        <source>New Tab</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+0"/> | 
				
			||||
 | 
					        <source>Enter a tab title:</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					</context> | 
				
			||||
 | 
					<context> | 
				
			||||
 | 
					    <name>qtmvvm_settings_xml</name> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location filename=".ts-dummy/settings.tsdummy.cpp" line="+4"/> | 
				
			||||
 | 
					        <source>property</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Text 1</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Value C</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Value A</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Another Section</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Value B</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Enter a nice name</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Value B+C</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Variant A</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>This is a tooltip</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Variant C</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Value A+B</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Sub-Group</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>&Check me</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Enter a &value</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>The value must be between 0 and 1</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Open &system settings</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Another main category</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Value A+C</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Variant B</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Choose a &font</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>This is another section</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>bool</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Select a &mode</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>I am a checkbox!</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Value A+B+C</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Enter a &number</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>You can use this to trigger whatever kind of action you need</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Text 2</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Enter a &website</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>Enter a &name</source> | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					    <message> | 
				
			||||
 | 
					        <location line="+1"/> | 
				
			||||
 | 
					        <source>https://example.org/test</source>
 | 
				
			||||
 | 
					        <translation type="unfinished"></translation> | 
				
			||||
 | 
					    </message> | 
				
			||||
 | 
					</context> | 
				
			||||
 | 
					</TS> | 
				
			||||
@ -0,0 +1,131 @@ | 
				
			|||||
 | 
					#include "accountmodel.h" | 
				
			||||
 | 
					#include "accountmodel_p.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QRemoteObjectReplica> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					using namespace QtMvvm; | 
				
			||||
 | 
					using namespace QtDataSync; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					AccountModel::AccountModel(QObject *parent) : | 
				
			||||
 | 
						QAbstractListModel(parent), | 
				
			||||
 | 
						d(new AccountModelPrivate()) | 
				
			||||
 | 
					{} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					AccountModel::~AccountModel() {} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void AccountModel::setup(AccountManager *manager) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						beginResetModel(); | 
				
			||||
 | 
						d->devices.clear(); | 
				
			||||
 | 
						if(d->manager) | 
				
			||||
 | 
							d->manager->disconnect(this); | 
				
			||||
 | 
						d->manager = manager; | 
				
			||||
 | 
						endResetModel(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						connect(d->manager, &AccountManager::accountDevices, | 
				
			||||
 | 
								this, &AccountModel::accountDevices); | 
				
			||||
 | 
						connect(d->manager, &AccountManager::importAccepted, | 
				
			||||
 | 
								this, &AccountModel::reload); | 
				
			||||
 | 
						connect(d->manager, &AccountManager::accountAccessGranted, | 
				
			||||
 | 
								this, &AccountModel::reload); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						if(d->manager->replica()->isInitialized()) | 
				
			||||
 | 
							d->manager->listDevices(); | 
				
			||||
 | 
						else { | 
				
			||||
 | 
							connect(d->manager->replica(), &QRemoteObjectReplica::initialized, | 
				
			||||
 | 
									d->manager, &AccountManager::listDevices); | 
				
			||||
 | 
						} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					QVariant AccountModel::headerData(int section, Qt::Orientation orientation, int role) const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if(orientation != Qt::Horizontal) | 
				
			||||
 | 
							return {}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						switch (section) { | 
				
			||||
 | 
						case 0: | 
				
			||||
 | 
							switch(role) { | 
				
			||||
 | 
							case NameRole: | 
				
			||||
 | 
								return tr("Name"); | 
				
			||||
 | 
							case FingerPrintRole: | 
				
			||||
 | 
								return tr("Fingerprint"); | 
				
			||||
 | 
							default: | 
				
			||||
 | 
								break; | 
				
			||||
 | 
							} | 
				
			||||
 | 
							break; | 
				
			||||
 | 
						case 1: | 
				
			||||
 | 
							if(role == Qt::DisplayRole) | 
				
			||||
 | 
								return tr("Fingerprint"); | 
				
			||||
 | 
							break; | 
				
			||||
 | 
						default: | 
				
			||||
 | 
							break; | 
				
			||||
 | 
						} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						return {}; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					int AccountModel::rowCount(const QModelIndex &parent) const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if (parent.isValid()) | 
				
			||||
 | 
							return 0; | 
				
			||||
 | 
						else | 
				
			||||
 | 
							return d->devices.size(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					QVariant AccountModel::data(const QModelIndex &index, int role) const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if (!index.isValid()) | 
				
			||||
 | 
							return QVariant(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						switch (index.column()) { | 
				
			||||
 | 
						case 0: | 
				
			||||
 | 
							switch(role) { | 
				
			||||
 | 
							case NameRole: | 
				
			||||
 | 
								return d->devices.value(index.row()).name(); | 
				
			||||
 | 
							case FingerPrintRole: | 
				
			||||
 | 
								return d->devices.value(index.row()).fingerprint(); | 
				
			||||
 | 
							default: | 
				
			||||
 | 
								break; | 
				
			||||
 | 
							} | 
				
			||||
 | 
							break; | 
				
			||||
 | 
						case 1: | 
				
			||||
 | 
							if(role == Qt::DisplayRole) | 
				
			||||
 | 
								return d->devices.value(index.row()).fingerprint(); | 
				
			||||
 | 
							break; | 
				
			||||
 | 
						default: | 
				
			||||
 | 
							break; | 
				
			||||
 | 
						} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						return {}; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					bool AccountModel::removeDevice(const QModelIndex &index) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if (!index.isValid()) | 
				
			||||
 | 
							return false; | 
				
			||||
 | 
						else { | 
				
			||||
 | 
							d->manager->removeDevice(d->devices.value(index.row())); | 
				
			||||
 | 
							return true; | 
				
			||||
 | 
						} | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void AccountModel::reload() | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if(d->manager) | 
				
			||||
 | 
							d->manager->listDevices(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void AccountModel::accountDevices(const QList<DeviceInfo> &devices) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						beginResetModel(); | 
				
			||||
 | 
						d->devices = devices; | 
				
			||||
 | 
						endResetModel(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// ------------- Private Implementation -------------
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					AccountModelPrivate::AccountModelPrivate() : | 
				
			||||
 | 
						manager(nullptr), | 
				
			||||
 | 
						devices() | 
				
			||||
 | 
					{} | 
				
			||||
@ -0,0 +1,51 @@ | 
				
			|||||
 | 
					#ifndef QTMVVM_ACCOUNTMODEL_H | 
				
			||||
 | 
					#define QTMVVM_ACCOUNTMODEL_H | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtCore/qabstractitemmodel.h> | 
				
			||||
 | 
					#include <QtCore/qscopedpointer.h> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtDataSync/accountmanager.h> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include "QtMvvmDataSyncCore/qtmvvmdatasynccore_global.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					namespace QtMvvm { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class AccountModelPrivate; | 
				
			||||
 | 
					class Q_MVVMDATASYNCCORE_EXPORT AccountModel : public QAbstractListModel | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						Q_OBJECT | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					public: | 
				
			||||
 | 
						enum Roles { | 
				
			||||
 | 
							NameRole = Qt::DisplayRole, | 
				
			||||
 | 
							FingerPrintRole = Qt::UserRole + 1 | 
				
			||||
 | 
						}; | 
				
			||||
 | 
						Q_ENUM(Roles) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						explicit AccountModel(QObject *parent = nullptr); | 
				
			||||
 | 
						~AccountModel(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						Q_INVOKABLE void setup(QtDataSync::AccountManager *manager); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; | 
				
			||||
 | 
						int rowCount(const QModelIndex &parent = QModelIndex()) const override; | 
				
			||||
 | 
						QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						Q_INVOKABLE bool removeDevice(const QModelIndex &index); | 
				
			||||
 | 
						Q_INVOKABLE inline bool removeDevice(int row) { | 
				
			||||
 | 
							return removeDevice(index(row)); | 
				
			||||
 | 
						} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					public Q_SLOTS: | 
				
			||||
 | 
						void reload(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					private Q_SLOTS: | 
				
			||||
 | 
						void accountDevices(const QList<QtDataSync::DeviceInfo> &devices); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					private: | 
				
			||||
 | 
						QScopedPointer<AccountModelPrivate> d; | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#endif // QTMVVM_ACCOUNTMODEL_H
 | 
				
			||||
@ -0,0 +1,20 @@ | 
				
			|||||
 | 
					#ifndef QTMVVM_ACCOUNTMODEL_P_H | 
				
			||||
 | 
					#define QTMVVM_ACCOUNTMODEL_P_H | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include "qtmvvmdatasynccore_global.h" | 
				
			||||
 | 
					#include "accountmodel.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					namespace QtMvvm { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class AccountModelPrivate | 
				
			||||
 | 
					{ | 
				
			||||
 | 
					public: | 
				
			||||
 | 
						AccountModelPrivate(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						QtDataSync::AccountManager *manager; | 
				
			||||
 | 
						QList<QtDataSync::DeviceInfo> devices; | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#endif // QTMVVM_ACCOUNTMODEL_P_H
 | 
				
			||||
@ -0,0 +1,11 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="UTF-8"?> | 
				
			||||
 | 
					<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> | 
				
			||||
 | 
						<mime-type type="application/x-datasync-account-data"> | 
				
			||||
 | 
							<comment>Account data of a datasync account as file export</comment> | 
				
			||||
 | 
							<comment xml:lang="en">Account data of a datasync account as file export</comment> | 
				
			||||
 | 
							<comment xml:lang="de">Account-Daten eines Datasync-Accounts als Dateiexport</comment> | 
				
			||||
 | 
							<icon name="x-datasync-account-data"/> | 
				
			||||
 | 
							<glob-deleteall/> | 
				
			||||
 | 
							<glob pattern="*.dsad"/> | 
				
			||||
 | 
						</mime-type> | 
				
			||||
 | 
					</mime-info> | 
				
			||||
@ -0,0 +1,422 @@ | 
				
			|||||
 | 
					#include "datasyncviewmodel.h" | 
				
			||||
 | 
					#include "datasyncviewmodel_p.h" | 
				
			||||
 | 
					#include "exportsetupviewmodel_p.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtCore/QStandardPaths> | 
				
			||||
 | 
					#include <QtCore/QFile> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtRemoteObjects/QRemoteObjectNode> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtMvvmCore/CoreApp> | 
				
			||||
 | 
					#include <QtMvvmCore/Messages> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtDataSync/SetupDoesNotExistException> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#undef logDebug | 
				
			||||
 | 
					#undef logInfo | 
				
			||||
 | 
					#undef logWarning | 
				
			||||
 | 
					#undef logCritical | 
				
			||||
 | 
					#include <QtMvvmCore/private/qtmvvm_logging_p.h> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					using namespace QtMvvm; | 
				
			||||
 | 
					using namespace QtDataSync; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					const QString DataSyncViewModel::paramSetup(QStringLiteral("setup")); | 
				
			||||
 | 
					const QString DataSyncViewModel::paramReplicaNode(QStringLiteral("node")); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					QVariantHash DataSyncViewModel::showParams(const QString &setup) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						return { | 
				
			||||
 | 
							{paramSetup, setup} | 
				
			||||
 | 
						}; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					QVariantHash DataSyncViewModel::showParams(QRemoteObjectNode *node) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						return { | 
				
			||||
 | 
							{paramReplicaNode, QVariant::fromValue(node)} | 
				
			||||
 | 
						}; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					DataSyncViewModel::DataSyncViewModel(QObject *parent) : | 
				
			||||
 | 
						ViewModel(parent), | 
				
			||||
 | 
						d(new DataSyncViewModelPrivate(this)) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						resetColorMap(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					DataSyncViewModel::~DataSyncViewModel() {} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					SyncManager *DataSyncViewModel::syncManager() const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						return d->syncManager; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					AccountManager *DataSyncViewModel::accountManager() const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						return d->accountManager; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					DataSyncViewModel::ColorMap DataSyncViewModel::colorMap() const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						return d->colorMap; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					QString DataSyncViewModel::statusString() const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if(!d->syncManager) | 
				
			||||
 | 
							return {}; | 
				
			||||
 | 
						auto state = d->syncManager->syncState(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						QString baseText = QStringLiteral("<font color=\"%1\">%2</font>") | 
				
			||||
 | 
										   .arg(d->colorMap.value(state).name()); | 
				
			||||
 | 
						switch (state) { | 
				
			||||
 | 
						case SyncManager::Initializing: | 
				
			||||
 | 
							return baseText.arg(tr("Connecting…")); | 
				
			||||
 | 
						case SyncManager::Downloading: | 
				
			||||
 | 
							return baseText.arg(tr("Downloading…")); | 
				
			||||
 | 
						case SyncManager::Uploading: | 
				
			||||
 | 
							return baseText.arg(tr("Uploading…")); | 
				
			||||
 | 
						case SyncManager::Synchronized: | 
				
			||||
 | 
							return baseText.arg(tr("Synchronized")); | 
				
			||||
 | 
						case SyncManager::Error: | 
				
			||||
 | 
							return baseText.arg(tr("Error!")); | 
				
			||||
 | 
						case SyncManager::Disconnected: | 
				
			||||
 | 
							return baseText.arg(tr("Disconnected")); | 
				
			||||
 | 
						default: | 
				
			||||
 | 
							Q_UNREACHABLE(); | 
				
			||||
 | 
							return QString(); | 
				
			||||
 | 
						} | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					AccountModel *DataSyncViewModel::accountModel() const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						return d->accountModel; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					QString DataSyncViewModel::formatFingerPrint(const QByteArray &fingerPrint) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						QByteArrayList res; | 
				
			||||
 | 
						for(char c : fingerPrint) | 
				
			||||
 | 
							res.append(QByteArray(1, c).toHex().toUpper()); | 
				
			||||
 | 
						return QString::fromUtf8(res.join(':')); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::showDeviceInfo() | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						Q_UNIMPLEMENTED(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::startExport() | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						showForResult<ExportSetupViewModel>(DataSyncViewModelPrivate::ExportRequestCode); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::startImport() | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						auto home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); | 
				
			||||
 | 
						getOpenFile(this, [this](QUrl url) { | 
				
			||||
 | 
							if(url.isValid()) { | 
				
			||||
 | 
								QSharedPointer<QIODevice> device; | 
				
			||||
 | 
								//TODO add support for android content device
 | 
				
			||||
 | 
								if(url.isLocalFile()) | 
				
			||||
 | 
									device.reset(new QFile(url.toLocalFile())); | 
				
			||||
 | 
								else { | 
				
			||||
 | 
									critical(tr("Import failed"), tr("Unsupported URL Scheme: %1").arg(url.scheme())); | 
				
			||||
 | 
									return; | 
				
			||||
 | 
								} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
								if(!device->open(QIODevice::ReadOnly | QIODevice::Text)) { | 
				
			||||
 | 
									critical(tr("Import failed"), | 
				
			||||
 | 
											 tr("Failed to open URL \"%1\" with error: %1") | 
				
			||||
 | 
											 .arg(url.toString()) | 
				
			||||
 | 
											 .arg(device->errorString())); | 
				
			||||
 | 
									return; | 
				
			||||
 | 
								} | 
				
			||||
 | 
								auto data = device->readAll(); | 
				
			||||
 | 
								device->close(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
								if(AccountManager::isTrustedImport(data)) { | 
				
			||||
 | 
									MessageConfig config{MessageConfig::TypeInputDialog, QMetaType::typeName(QMetaType::QString)}; | 
				
			||||
 | 
									config.setTitle(tr("Import account data")) | 
				
			||||
 | 
											.setText(tr("Enter the password to decrypt the account data. " | 
				
			||||
 | 
														"Then choose whether you want to keep you local data or not:")) | 
				
			||||
 | 
											.setButtons(MessageConfig::YesToAll | MessageConfig::Yes | MessageConfig::Cancel) //TODO adjust to get ideal placement
 | 
				
			||||
 | 
											.setButtonText(MessageConfig::YesToAll, tr("Reset data")) | 
				
			||||
 | 
											.setButtonText(MessageConfig::Yes, tr("Keep data")) | 
				
			||||
 | 
											.setViewProperties({ | 
				
			||||
 | 
																   {QStringLiteral("echoMode"), 2} //QLineEdit::Password
 | 
				
			||||
 | 
															   }); | 
				
			||||
 | 
									auto res = CoreApp::showDialog(config); | 
				
			||||
 | 
									connect(res, &MessageResult::dialogDone, this, [this, res, data](MessageConfig::StandardButton btn) { | 
				
			||||
 | 
										switch (btn) { | 
				
			||||
 | 
										case MessageConfig::YesToAll: | 
				
			||||
 | 
											d->performImport(true, res->result().toString(), data, false); | 
				
			||||
 | 
											break; | 
				
			||||
 | 
										case MessageConfig::Yes: | 
				
			||||
 | 
											d->performImport(true, res->result().toString(), data, true); | 
				
			||||
 | 
											break; | 
				
			||||
 | 
										default: | 
				
			||||
 | 
											break; | 
				
			||||
 | 
										} | 
				
			||||
 | 
									}); | 
				
			||||
 | 
								} else { | 
				
			||||
 | 
									MessageConfig config{MessageConfig::TypeMessageBox, MessageConfig::SubTypeQuestion}; | 
				
			||||
 | 
									config.setTitle(tr("Import account data")) | 
				
			||||
 | 
											.setText(tr("Keep the local data after changing the account?")) | 
				
			||||
 | 
											.setButtons(MessageConfig::YesToAll | MessageConfig::Yes | MessageConfig::Cancel) //TODO adjust to get ideal placement
 | 
				
			||||
 | 
											.setButtonText(MessageConfig::YesToAll, tr("Reset data")) | 
				
			||||
 | 
											.setButtonText(MessageConfig::Yes, tr("Keep data")); | 
				
			||||
 | 
									auto res = CoreApp::showDialog(config); | 
				
			||||
 | 
									connect(res, &MessageResult::dialogDone, this, [this, res, data](MessageConfig::StandardButton btn) { | 
				
			||||
 | 
										switch (btn) { | 
				
			||||
 | 
										case MessageConfig::YesToAll: | 
				
			||||
 | 
											d->performImport(false, {}, data, false); | 
				
			||||
 | 
											break; | 
				
			||||
 | 
										case MessageConfig::Yes: | 
				
			||||
 | 
											d->performImport(false, {}, data, true); | 
				
			||||
 | 
											break; | 
				
			||||
 | 
										default: | 
				
			||||
 | 
											break; | 
				
			||||
 | 
										} | 
				
			||||
 | 
									}); | 
				
			||||
 | 
								} | 
				
			||||
 | 
							} | 
				
			||||
 | 
						}, tr("Import account data"), | 
				
			||||
 | 
						{QStringLiteral("application/x-datasync-account-data"), QStringLiteral("application/octet-stream")}, | 
				
			||||
 | 
						QUrl::fromLocalFile(home)); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::performReset() | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						MessageConfig config {MessageConfig::TypeMessageBox, MessageConfig::SubTypeQuestion}; | 
				
			||||
 | 
						config.setTitle(tr("Reset Account?")) | 
				
			||||
 | 
								.setText(tr("Do you want to reset your account? " | 
				
			||||
 | 
											"You will loose the connection to all other devices and get a new identity." | 
				
			||||
 | 
											"You can either keep your data or reset it as well." | 
				
			||||
 | 
											"This cannot be undone!")) | 
				
			||||
 | 
								.setButtons(MessageConfig::YesToAll | MessageConfig::Yes | MessageConfig::Cancel) //TODO adjust to get ideal placement
 | 
				
			||||
 | 
								.setButtonText(MessageConfig::YesToAll, tr("Reset data")) | 
				
			||||
 | 
								.setButtonText(MessageConfig::Yes, tr("Keep data")); | 
				
			||||
 | 
						auto res = CoreApp::showDialog(config); | 
				
			||||
 | 
						connect(res, &MessageResult::dialogDone, this, [this](MessageConfig::StandardButton btn) { | 
				
			||||
 | 
							switch (btn) { | 
				
			||||
 | 
							case MessageConfig::YesToAll: | 
				
			||||
 | 
								d->accountManager->resetAccount(false); | 
				
			||||
 | 
								break; | 
				
			||||
 | 
							case MessageConfig::Yes: | 
				
			||||
 | 
								d->accountManager->resetAccount(true); | 
				
			||||
 | 
								break; | 
				
			||||
 | 
							default: | 
				
			||||
 | 
								break; | 
				
			||||
 | 
							} | 
				
			||||
 | 
						}); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::changeRemote() | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						Q_UNIMPLEMENTED(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::startNetworkExchange() | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						Q_UNIMPLEMENTED(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::setColorMap(DataSyncViewModel::ColorMap colorMap) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if (d->colorMap == colorMap) | 
				
			||||
 | 
							return; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						d->colorMap = colorMap; | 
				
			||||
 | 
						emit colorMapChanged(d->colorMap); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::resetColorMap() | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						d->colorMap.clear(); | 
				
			||||
 | 
						d->colorMap.insert(SyncManager::Initializing, Qt::darkCyan); | 
				
			||||
 | 
						d->colorMap.insert(SyncManager::Downloading, Qt::darkCyan); | 
				
			||||
 | 
						d->colorMap.insert(SyncManager::Uploading, Qt::darkCyan); | 
				
			||||
 | 
						d->colorMap.insert(SyncManager::Synchronized, Qt::darkGreen); | 
				
			||||
 | 
						d->colorMap.insert(SyncManager::Error, Qt::darkRed); | 
				
			||||
 | 
						d->colorMap.insert(SyncManager::Disconnected, Qt::darkYellow); | 
				
			||||
 | 
						emit colorMapChanged(d->colorMap); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::showImportDialog(LoginRequest request) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if(request.handled()) | 
				
			||||
 | 
							return; | 
				
			||||
 | 
						question(tr("Login requested!"), | 
				
			||||
 | 
								 tr("<p>A device wants to log into your account:</p>" | 
				
			||||
 | 
									"<p>Name: %1<br/>" | 
				
			||||
 | 
									"Fingerprint: %2</p>" | 
				
			||||
 | 
									"<p>Do you want accept the request?</p>") | 
				
			||||
 | 
								 .arg(request.device().name()) | 
				
			||||
 | 
								 .arg(formatFingerPrint(request.device().fingerprint())), | 
				
			||||
 | 
								 this, [this, request](bool ok) { | 
				
			||||
 | 
							auto req = request; | 
				
			||||
 | 
							if(!req.handled()) { | 
				
			||||
 | 
								if(ok) | 
				
			||||
 | 
									req.accept(); | 
				
			||||
 | 
								else | 
				
			||||
 | 
									req.reject(); | 
				
			||||
 | 
							} | 
				
			||||
 | 
						}); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::showImportAccepted() | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						information(tr("Import accepted"), | 
				
			||||
 | 
									tr("The partner has accepted the import. You are now logged in.")); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::showAccessGranted(const QUuid &id) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						d->pendingGrants.insert(id); | 
				
			||||
 | 
						//no need to call list devices, is done by the model
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::triggerGranted(const QList<DeviceInfo> &devices) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						for(auto device : devices) { | 
				
			||||
 | 
							if(d->pendingGrants.remove(device.deviceId())) { | 
				
			||||
 | 
								information(tr("Account access granted"), | 
				
			||||
 | 
											tr("<p>Account access has been granted to device:</p>" | 
				
			||||
 | 
											   "<p>Name: %1<br/>" | 
				
			||||
 | 
											   "Fingerprint: %2</p>") | 
				
			||||
 | 
											.arg(device.name()) | 
				
			||||
 | 
											.arg(formatFingerPrint(device.fingerprint()))); | 
				
			||||
 | 
							} | 
				
			||||
 | 
						} | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::onInit(const QVariantHash ¶ms) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						try { | 
				
			||||
 | 
							if(params.contains(paramReplicaNode)) { | 
				
			||||
 | 
								auto node = params.value(paramReplicaNode).value<QRemoteObjectNode*>(); | 
				
			||||
 | 
								d->syncManager = new SyncManager(node, this); | 
				
			||||
 | 
								d->accountManager = new AccountManager(node, this); | 
				
			||||
 | 
							} else { | 
				
			||||
 | 
								auto setup = params.value(paramSetup, QtDataSync::DefaultSetup).toString(); | 
				
			||||
 | 
								d->syncManager = new SyncManager(setup, this); | 
				
			||||
 | 
								d->accountManager = new AccountManager(setup, this); | 
				
			||||
 | 
							} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
							//sync manager
 | 
				
			||||
 | 
							connect(d->syncManager, &SyncManager::syncStateChanged, | 
				
			||||
 | 
									this, &DataSyncViewModel::statusStringChanged); | 
				
			||||
 | 
							connect(d->syncManager, &SyncManager::lastErrorChanged, | 
				
			||||
 | 
									this, &DataSyncViewModel::statusStringChanged); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
							//account manager
 | 
				
			||||
 | 
							connect(d->accountManager, &AccountManager::loginRequested, | 
				
			||||
 | 
									this, &DataSyncViewModel::showImportDialog); | 
				
			||||
 | 
							connect(d->accountManager, &AccountManager::importAccepted, | 
				
			||||
 | 
									this, &DataSyncViewModel::showImportAccepted); | 
				
			||||
 | 
							connect(d->accountManager, &AccountManager::accountAccessGranted, | 
				
			||||
 | 
									this, &DataSyncViewModel::showAccessGranted); | 
				
			||||
 | 
							connect(d->accountManager, &AccountManager::accountDevices, | 
				
			||||
 | 
									this, &DataSyncViewModel::triggerGranted); | 
				
			||||
 | 
							d->accountModel->setup(d->accountManager); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
							emit syncManagerChanged(d->syncManager); | 
				
			||||
 | 
							emit accountManagerChanged(d->accountManager); | 
				
			||||
 | 
						} catch(SetupDoesNotExistException &e) { | 
				
			||||
 | 
							logCritical() << "Failed to init DataSyncViewModel with error:" | 
				
			||||
 | 
										  << e.what(); | 
				
			||||
 | 
						} | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModel::onResult(quint32 requestCode, const QVariant &result) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						switch (requestCode) { | 
				
			||||
 | 
						case DataSyncViewModelPrivate::ExportRequestCode: | 
				
			||||
 | 
							if(result.isValid()) { | 
				
			||||
 | 
								auto res = ExportSetupViewModel::result(result); | 
				
			||||
 | 
								d->performExport(std::get<0>(res), std::get<1>(res), std::get<2>(res)); | 
				
			||||
 | 
							} | 
				
			||||
 | 
							break; | 
				
			||||
 | 
						default: | 
				
			||||
 | 
							break; | 
				
			||||
 | 
						} | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					// ------------- Private Implementation -------------
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					QtMvvm::DataSyncViewModelPrivate::DataSyncViewModelPrivate(DataSyncViewModel *q_ptr) : | 
				
			||||
 | 
						q(q_ptr), | 
				
			||||
 | 
						syncManager(nullptr), | 
				
			||||
 | 
						accountManager(nullptr), | 
				
			||||
 | 
						colorMap(), | 
				
			||||
 | 
						accountModel(new AccountModel(q_ptr)) | 
				
			||||
 | 
					{} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModelPrivate::performExport(bool trusted, bool includeServer, const QString &password) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						auto home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); | 
				
			||||
 | 
						getSaveFile(q, [this, trusted, includeServer, password](QUrl url) { | 
				
			||||
 | 
							if(url.isValid()) { | 
				
			||||
 | 
								QSharedPointer<QIODevice> device; | 
				
			||||
 | 
								//TODO add support for android content device
 | 
				
			||||
 | 
								if(url.isLocalFile()) | 
				
			||||
 | 
									device.reset(new QFile(url.toLocalFile())); | 
				
			||||
 | 
								else { | 
				
			||||
 | 
									critical(DataSyncViewModel::tr("Export failed"), | 
				
			||||
 | 
											 DataSyncViewModel::tr("Unsupported URL Scheme: %1").arg(url.scheme())); | 
				
			||||
 | 
									return; | 
				
			||||
 | 
								} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
								if(!device->open(QIODevice::WriteOnly | QIODevice::Text)) { | 
				
			||||
 | 
									critical(DataSyncViewModel::tr("Export failed"), | 
				
			||||
 | 
											 DataSyncViewModel::tr("Failed to open URL \"%1\" with error: %1") | 
				
			||||
 | 
											 .arg(url.toString()) | 
				
			||||
 | 
											 .arg(device->errorString())); | 
				
			||||
 | 
									return; | 
				
			||||
 | 
								} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
								QPointer<DataSyncViewModel> qPtr(q); | 
				
			||||
 | 
								auto resFn = [this, qPtr, device](QByteArray data) { | 
				
			||||
 | 
									if(!qPtr) | 
				
			||||
 | 
										return; | 
				
			||||
 | 
									device->write(data); | 
				
			||||
 | 
									device->close(); | 
				
			||||
 | 
									information(DataSyncViewModel::tr("Export completed"), | 
				
			||||
 | 
												DataSyncViewModel::tr("Data was successfully exported.")); | 
				
			||||
 | 
								}; | 
				
			||||
 | 
								auto errFn = [this, qPtr, device](QString error){ | 
				
			||||
 | 
									if(!qPtr) | 
				
			||||
 | 
										return; | 
				
			||||
 | 
									critical(DataSyncViewModel::tr("Export failed"), error); | 
				
			||||
 | 
								}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
								if(trusted) | 
				
			||||
 | 
									accountManager->exportAccountTrusted(includeServer, password, resFn, errFn); | 
				
			||||
 | 
								else | 
				
			||||
 | 
									accountManager->exportAccount(includeServer, resFn, errFn); | 
				
			||||
 | 
							} | 
				
			||||
 | 
						}, DataSyncViewModel::tr("Export account data"), | 
				
			||||
 | 
						{QStringLiteral("application/x-datasync-account-data"), QStringLiteral("application/octet-stream")}, | 
				
			||||
 | 
						QUrl::fromLocalFile(home)); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void DataSyncViewModelPrivate::performImport(bool trusted, const QString &password, const QByteArray &data, bool keepData) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						QPointer<DataSyncViewModel> qPtr(q); | 
				
			||||
 | 
						auto resFn = [this, qPtr](bool ok, QString error) { | 
				
			||||
 | 
							if(!qPtr) | 
				
			||||
 | 
								return; | 
				
			||||
 | 
							if(ok) { | 
				
			||||
 | 
								information(DataSyncViewModel::tr("Import completed"), | 
				
			||||
 | 
											DataSyncViewModel::tr("Data was successfully imported.")); | 
				
			||||
 | 
							} else | 
				
			||||
 | 
								critical(DataSyncViewModel::tr("Import failed"), error); | 
				
			||||
 | 
						}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						if(trusted) | 
				
			||||
 | 
							accountManager->importAccountTrusted(data, password, resFn, keepData); | 
				
			||||
 | 
						else | 
				
			||||
 | 
							accountManager->importAccount(data, resFn, keepData); | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,86 @@ | 
				
			|||||
 | 
					#ifndef QTMVVM_DATASYNCVIEWMODEL_H | 
				
			||||
 | 
					#define QTMVVM_DATASYNCVIEWMODEL_H | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtCore/qmap.h> | 
				
			||||
 | 
					#include <QtCore/qscopedpointer.h> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtGui/qcolor.h> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtMvvmCore/viewmodel.h> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtDataSync/syncmanager.h> | 
				
			||||
 | 
					#include <QtDataSync/accountmanager.h> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include "QtMvvmDataSyncCore/qtmvvmdatasynccore_global.h" | 
				
			||||
 | 
					#include "QtMvvmDataSyncCore/accountmodel.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					namespace QtMvvm { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class DataSyncViewModelPrivate; | 
				
			||||
 | 
					class Q_MVVMDATASYNCCORE_EXPORT DataSyncViewModel : public ViewModel | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						Q_OBJECT | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						Q_PROPERTY(QtDataSync::SyncManager* syncManager READ syncManager NOTIFY syncManagerChanged) | 
				
			||||
 | 
						Q_PROPERTY(QtDataSync::AccountManager* accountManager READ accountManager NOTIFY accountManagerChanged) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						Q_PROPERTY(ColorMap colorMap READ colorMap WRITE setColorMap RESET resetColorMap NOTIFY colorMapChanged) | 
				
			||||
 | 
						Q_PROPERTY(QString statusString READ statusString NOTIFY statusStringChanged) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						Q_PROPERTY(QtMvvm::AccountModel* accountModel READ accountModel CONSTANT) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					public: | 
				
			||||
 | 
						typedef QMap<QtDataSync::SyncManager::SyncState, QColor> ColorMap; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						static const QString paramSetup; | 
				
			||||
 | 
						static const QString paramReplicaNode; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						static QVariantHash showParams(const QString &setup); | 
				
			||||
 | 
						static QVariantHash showParams(QRemoteObjectNode *node); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						Q_INVOKABLE explicit DataSyncViewModel(QObject *parent = nullptr); | 
				
			||||
 | 
						~DataSyncViewModel(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						QtDataSync::SyncManager* syncManager() const; | 
				
			||||
 | 
						QtDataSync::AccountManager* accountManager() const; | 
				
			||||
 | 
						ColorMap colorMap() const; | 
				
			||||
 | 
						QString statusString() const; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						AccountModel *accountModel() const; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						Q_INVOKABLE static QString formatFingerPrint(const QByteArray &fingerPrint); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					public Q_SLOTS: | 
				
			||||
 | 
						void showDeviceInfo(); | 
				
			||||
 | 
						void startExport(); | 
				
			||||
 | 
						void startImport(); | 
				
			||||
 | 
						void performReset(); | 
				
			||||
 | 
						void changeRemote(); | 
				
			||||
 | 
						void startNetworkExchange(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						void setColorMap(ColorMap colorMap); | 
				
			||||
 | 
						void resetColorMap(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					private Q_SLOTS: | 
				
			||||
 | 
						void showImportDialog(QtDataSync::LoginRequest request); | 
				
			||||
 | 
						void showImportAccepted(); | 
				
			||||
 | 
						void showAccessGranted(const QUuid &id); | 
				
			||||
 | 
						void triggerGranted(const QList<QtDataSync::DeviceInfo> &devices); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Q_SIGNALS: | 
				
			||||
 | 
						void syncManagerChanged(QtDataSync::SyncManager* syncManager); | 
				
			||||
 | 
						void accountManagerChanged(QtDataSync::AccountManager* accountManager); | 
				
			||||
 | 
						void colorMapChanged(ColorMap colorMap); | 
				
			||||
 | 
						void statusStringChanged(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					protected: | 
				
			||||
 | 
						void onInit(const QVariantHash ¶ms) override; | 
				
			||||
 | 
						void onResult(quint32 requestCode, const QVariant &result) override; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					private: | 
				
			||||
 | 
						QScopedPointer<DataSyncViewModelPrivate> d; | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#endif // QTMVVM_DATASYNCVIEWMODEL_H
 | 
				
			||||
@ -0,0 +1,32 @@ | 
				
			|||||
 | 
					#ifndef QTMVVM_DATASYNCVIEWMODEL_P_H | 
				
			||||
 | 
					#define QTMVVM_DATASYNCVIEWMODEL_P_H | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtCore/QSet> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include "qtmvvmdatasynccore_global.h" | 
				
			||||
 | 
					#include "datasyncviewmodel.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					namespace QtMvvm { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class DataSyncViewModelPrivate | 
				
			||||
 | 
					{ | 
				
			||||
 | 
					public: | 
				
			||||
 | 
						static const quint32 ExportRequestCode = 0xb201; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						DataSyncViewModelPrivate(DataSyncViewModel *q_ptr); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						DataSyncViewModel *q; | 
				
			||||
 | 
						QtDataSync::SyncManager *syncManager; | 
				
			||||
 | 
						QtDataSync::AccountManager *accountManager; | 
				
			||||
 | 
						DataSyncViewModel::ColorMap colorMap; | 
				
			||||
 | 
						AccountModel *accountModel; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						QSet<QUuid> pendingGrants; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						void performExport(bool trusted, bool includeServer, const QString &password); | 
				
			||||
 | 
						void performImport(bool trusted, const QString &password, const QByteArray &data, bool keepData); | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#endif // QTMVVM_DATASYNCVIEWMODEL_P_H
 | 
				
			||||
@ -0,0 +1,82 @@ | 
				
			|||||
 | 
					#include "exportsetupviewmodel_p.h" | 
				
			||||
 | 
					using namespace QtMvvm; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					std::tuple<bool, bool, QString> ExportSetupViewModel::result(const QVariant &data) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						auto map = data.toHash(); | 
				
			||||
 | 
						return std::make_tuple(map.value(QStringLiteral("trusted")).toBool(), | 
				
			||||
 | 
											   map.value(QStringLiteral("includeServer")).toBool(), | 
				
			||||
 | 
											   map.value(QStringLiteral("password")).toString()); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					ExportSetupViewModel::ExportSetupViewModel(QObject *parent) : | 
				
			||||
 | 
						ViewModel(parent), | 
				
			||||
 | 
						_trusted(false), | 
				
			||||
 | 
						_includeServer(false), | 
				
			||||
 | 
						_password() | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						connect(this, &ExportSetupViewModel::trustedChanged, | 
				
			||||
 | 
								this, &ExportSetupViewModel::validChanged); | 
				
			||||
 | 
						connect(this, &ExportSetupViewModel::passwordChanged, | 
				
			||||
 | 
								this, &ExportSetupViewModel::validChanged); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					bool ExportSetupViewModel::trusted() const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						return _trusted; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					bool ExportSetupViewModel::includeServer() const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						return _includeServer; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					QString ExportSetupViewModel::password() const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						return _password; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					bool ExportSetupViewModel::isValid() const | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						return !_trusted || !_password.isEmpty(); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					bool ExportSetupViewModel::completeSetup() | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if(!isValid()) | 
				
			||||
 | 
							return false; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						QVariantHash hash; | 
				
			||||
 | 
						hash[QStringLiteral("trusted")] = _trusted; | 
				
			||||
 | 
						hash[QStringLiteral("includeServer")] = _includeServer; | 
				
			||||
 | 
						hash[QStringLiteral("password")] = _trusted ? _password : QString(); | 
				
			||||
 | 
						emit resultReady(hash); | 
				
			||||
 | 
						return true; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void ExportSetupViewModel::setTrusted(bool trusted) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if (_trusted == trusted) | 
				
			||||
 | 
							return; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						_trusted = trusted; | 
				
			||||
 | 
						emit trustedChanged(_trusted); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void ExportSetupViewModel::setIncludeServer(bool includeServer) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if (_includeServer == includeServer) | 
				
			||||
 | 
							return; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						_includeServer = includeServer; | 
				
			||||
 | 
						emit includeServerChanged(_includeServer); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					void ExportSetupViewModel::setPassword(QString password) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if (_password == password) | 
				
			||||
 | 
							return; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						_password = password; | 
				
			||||
 | 
						emit passwordChanged(_password); | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,53 @@ | 
				
			|||||
 | 
					#ifndef QTMVVM_EXPORTSETUPVIEWMODEL_P_H | 
				
			||||
 | 
					#define QTMVVM_EXPORTSETUPVIEWMODEL_P_H | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <tuple> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtMvvmCore/ViewModel> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include "qtmvvmdatasynccore_global.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					namespace QtMvvm { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class Q_MVVMDATASYNCCORE_EXPORT ExportSetupViewModel : public ViewModel | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						Q_OBJECT | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						Q_PROPERTY(bool trusted READ trusted WRITE setTrusted NOTIFY trustedChanged) | 
				
			||||
 | 
						Q_PROPERTY(bool includeServer READ includeServer WRITE setIncludeServer NOTIFY includeServerChanged) | 
				
			||||
 | 
						Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						Q_PROPERTY(bool valid READ isValid NOTIFY validChanged) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					public: | 
				
			||||
 | 
						static std::tuple<bool, bool, QString> result(const QVariant &data); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						Q_INVOKABLE explicit ExportSetupViewModel(QObject *parent = nullptr); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						bool trusted() const; | 
				
			||||
 | 
						bool includeServer() const; | 
				
			||||
 | 
						QString password() const; | 
				
			||||
 | 
						bool isValid() const; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					public Q_SLOTS: | 
				
			||||
 | 
						bool completeSetup(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						void setTrusted(bool trusted); | 
				
			||||
 | 
						void setIncludeServer(bool includeServer); | 
				
			||||
 | 
						void setPassword(QString password); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Q_SIGNALS: | 
				
			||||
 | 
						void trustedChanged(bool trusted); | 
				
			||||
 | 
						void includeServerChanged(bool includeServer); | 
				
			||||
 | 
						void passwordChanged(QString password); | 
				
			||||
 | 
						void validChanged(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					private: | 
				
			||||
 | 
						bool _trusted; | 
				
			||||
 | 
						QString _password; | 
				
			||||
 | 
						bool _includeServer; | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#endif // QTMVVM_EXPORTSETUPVIEWMODEL_P_H
 | 
				
			||||
@ -0,0 +1,43 @@ | 
				
			|||||
 | 
					TARGET = QtMvvmDataSyncCore | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					QT = core gui mvvmcore datasync mvvmcore-private | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					HEADERS += \ | 
				
			||||
 | 
						qtmvvmdatasynccore_global.h \ | 
				
			||||
 | 
						datasyncviewmodel.h \ | 
				
			||||
 | 
						datasyncviewmodel_p.h \ | 
				
			||||
 | 
						accountmodel.h \ | 
				
			||||
 | 
						accountmodel_p.h \ | 
				
			||||
 | 
						exportsetupviewmodel_p.h | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					SOURCES += \ | 
				
			||||
 | 
						datasyncviewmodel.cpp \ | 
				
			||||
 | 
						accountmodel.cpp \ | 
				
			||||
 | 
						exportsetupviewmodel.cpp | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					TRANSLATIONS += \ | 
				
			||||
 | 
						translations/qtmvvmdatasynccore_de.ts \ | 
				
			||||
 | 
						translations/qtmvvmdatasynccore_template.ts | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					DISTFILES += $$TRANSLATIONS \ | 
				
			||||
 | 
						application-x-datasync-account-data.xml | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					qpmx_ts_target.path = $$[QT_INSTALL_TRANSLATIONS] | 
				
			||||
 | 
					qpmx_ts_target.depends += lrelease | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					load(qt_module) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					win32 { | 
				
			||||
 | 
						QMAKE_TARGET_PRODUCT = "$$TARGET" | 
				
			||||
 | 
						QMAKE_TARGET_COMPANY = "Skycoder42" | 
				
			||||
 | 
						QMAKE_TARGET_COPYRIGHT = "Felix Barz" | 
				
			||||
 | 
					} else:mac { | 
				
			||||
 | 
						QMAKE_TARGET_BUNDLE_PREFIX = "com.skycoder42." | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					!ReleaseBuild:!DebugBuild:!system(qpmx -d $$shell_quote($$_PRO_FILE_PWD_) --qmake-run init $$QPMX_EXTRA_OPTIONS $$shell_quote($$QMAKE_QMAKE) $$shell_quote($$OUT_PWD)): error(qpmx initialization failed. Check the compilation log for details.) | 
				
			||||
 | 
					else: include($$OUT_PWD/qpmx_generated.pri) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					qpmx_ts_target.files -= $$OUT_PWD/$$QPMX_WORKINGDIR/qtmvvmdatasynccore_template.qm | 
				
			||||
 | 
					qpmx_ts_target.files += translations/qtmvvmdatasynccore_template.ts | 
				
			||||
 | 
					
 | 
				
			||||
@ -0,0 +1,14 @@ | 
				
			|||||
 | 
					{ | 
				
			||||
 | 
					    "dependencies": [], | 
				
			||||
 | 
					    "license": { | 
				
			||||
 | 
					        "file": "", | 
				
			||||
 | 
					        "name": "" | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    "prcFile": "", | 
				
			||||
 | 
					    "priFile": "", | 
				
			||||
 | 
					    "priIncludes": [ | 
				
			||||
 | 
					    ], | 
				
			||||
 | 
					    "publishers": { | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    "source": false | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,12 @@ | 
				
			|||||
 | 
					#ifndef QTMVVMDATASYNCCORE_GLOBAL_H | 
				
			||||
 | 
					#define QTMVVMDATASYNCCORE_GLOBAL_H | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtCore/qglobal.h> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#if defined(QT_BUILD_MVVMDATASYNCCORE_LIB) | 
				
			||||
 | 
					#	define Q_MVVMDATASYNCCORE_EXPORT Q_DECL_EXPORT | 
				
			||||
 | 
					#else | 
				
			||||
 | 
					#	define Q_MVVMDATASYNCCORE_EXPORT Q_DECL_IMPORT | 
				
			||||
 | 
					#endif | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#endif // QTMVVMDATASYNCCORE_GLOBAL_H
 | 
				
			||||
@ -0,0 +1,4 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
 | 
					<!DOCTYPE TS> | 
				
			||||
 | 
					<TS version="2.1" language="de_DE"> | 
				
			||||
 | 
					</TS> | 
				
			||||
@ -0,0 +1,4 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
 | 
					<!DOCTYPE TS> | 
				
			||||
 | 
					<TS version="2.1"> | 
				
			||||
 | 
					</TS> | 
				
			||||
					Loading…
					
					
				
		Reference in new issue