Browse Source

implemented central ds widgets ui

pull/2/head
Skycoder42 7 years ago
parent
commit
23e48e35e2
  1. 10
      examples/mvvmdatasynccore/DataSyncSampleCore/DataSyncSampleCore.pro
  2. 22
      examples/mvvmdatasynccore/DataSyncSampleCore/docker-compose.yaml
  3. 4
      examples/mvvmdatasynccore/DataSyncSampleCore/samplecoreapp.cpp
  4. 8
      src/mvvmdatasynccore/accountmodel.cpp
  5. 1
      src/mvvmdatasynccore/accountmodel.h
  6. 14
      src/mvvmdatasynccore/datasyncviewmodel.cpp
  7. 3
      src/mvvmdatasynccore/datasyncviewmodel.h
  8. 112
      src/mvvmdatasyncwidgets/datasyncwindow.cpp
  9. 16
      src/mvvmdatasyncwidgets/datasyncwindow.h
  10. 316
      src/mvvmdatasyncwidgets/datasyncwindow.ui
  11. 2
      src/mvvmdatasyncwidgets/datasyncwindow_p.h
  12. 4
      src/mvvmquick/quickpresenter.cpp
  13. 26
      src/mvvmwidgets/widgetspresenter.cpp

10
examples/mvvmdatasynccore/DataSyncSampleCore/DataSyncSampleCore.pro

@ -7,13 +7,15 @@ TARGET = DataSyncSampleCore
HEADERS += \
samplecoreapp.h \
sampleviewmodel.h \
sampledata.h
sampleviewmodel.h \
sampledata.h
SOURCES += \
samplecoreapp.cpp \
sampleviewmodel.cpp \
sampledata.cpp
sampleviewmodel.cpp \
sampledata.cpp
OTHER_FILES += docker-compose.yaml
target.path = $$[QT_INSTALL_EXAMPLES]/mvvmdatasynccore/$$TARGET
INSTALLS += target

22
examples/mvvmdatasynccore/DataSyncSampleCore/docker-compose.yaml

@ -0,0 +1,22 @@
version: '2.2'
services:
datasync_postgres:
container_name: datasync_postgres
image: postgres:latest
environment:
POSTGRES_PASSWORD: baum42
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- datasync_postgres_data:/var/lib/postgresql/data/pgdata
datasync_qdsapp:
container_name: datasync_qdsapp
image: skycoder42/qdsapp:latest
depends_on:
- datasync_postgres
ports:
- "4242:4242/tcp"
environment:
QDSAPP_DATABASE_HOST: datasync_postgres
QDSAPP_DATABASE_PASSWORD: baum42
volumes:
datasync_postgres_data:

4
examples/mvvmdatasynccore/DataSyncSampleCore/samplecoreapp.cpp

@ -26,7 +26,9 @@ int SampleCoreApp::startApp(const QStringList &arguments)
setup = arguments.value(1);
try {
QtDataSync::Setup().create(setup);
QtDataSync::Setup()
.setRemoteConfiguration(QUrl(QStringLiteral("ws://localhost:4242")))
.create(setup);
show<SampleViewModel>();
return EXIT_SUCCESS;
} catch (QException &e) {

8
src/mvvmdatasynccore/accountmodel.cpp

@ -73,6 +73,14 @@ int AccountModel::rowCount(const QModelIndex &parent) const
return d->devices.size();
}
int AccountModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
else
return 2;
}
QVariant AccountModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())

1
src/mvvmdatasynccore/accountmodel.h

@ -29,6 +29,7 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_INVOKABLE bool removeDevice(const QModelIndex &index);

14
src/mvvmdatasynccore/datasyncviewmodel.cpp

@ -102,6 +102,15 @@ QString DataSyncViewModel::formatFingerPrint(const QByteArray &fingerPrint)
return QString::fromUtf8(res.join(':'));
}
void DataSyncViewModel::syncOrConnect()
{
if(d->syncManager->syncState() == SyncManager::Disconnected ||
d->syncManager->syncState() == SyncManager::Error)
d->syncManager->reconnect();
else
d->syncManager->synchronize();
}
void DataSyncViewModel::showDeviceInfo()
{
Q_UNIMPLEMENTED();
@ -192,8 +201,8 @@ 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."
"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"))
@ -324,6 +333,7 @@ void DataSyncViewModel::onInit(const QVariantHash &params)
emit syncManagerChanged(d->syncManager);
emit accountManagerChanged(d->accountManager);
emit ready();
} catch(SetupDoesNotExistException &e) {
logCritical() << "Failed to init DataSyncViewModel with error:"
<< e.what();

3
src/mvvmdatasynccore/datasyncviewmodel.h

@ -51,6 +51,7 @@ public:
Q_INVOKABLE static QString formatFingerPrint(const QByteArray &fingerPrint);
public Q_SLOTS:
void syncOrConnect();
void showDeviceInfo();
void startExport();
void startImport();
@ -73,6 +74,8 @@ Q_SIGNALS:
void colorMapChanged(ColorMap colorMap);
void statusStringChanged();
void ready();
protected:
void onInit(const QVariantHash &params) override;
void onResult(quint32 requestCode, const QVariant &result) override;

112
src/mvvmdatasyncwidgets/datasyncwindow.cpp

@ -1,20 +1,128 @@
#include "datasyncwindow.h"
#include "datasyncwindow_p.h"
#include "ui_datasyncwindow.h"
#include <QtMvvmCore/Binding>
#include <QtWidgets/QMenu>
using namespace QtMvvm;
using namespace QtDataSync;
DataSyncWindow::DataSyncWindow(QtMvvm::ViewModel *viewModel, QWidget *parent) :
QWidget(parent, Qt::Window),
d(new DataSyncWindowPrivate(this, viewModel))
d(new DataSyncWindowPrivate(viewModel))
{
d->ui->setupUi(this);
//ui setup
d->ui->identityButton->setDefaultAction(d->ui->actionEdit_Identity);
d->ui->treeView->addActions({
d->ui->actionRe_load_Device_List,
d->ui->action_Remove_Device
});
auto accountMenu = new QMenu(d->ui->accountButton);
accountMenu->addAction(d->ui->action_Network_exchange);
accountMenu->addAction(d->ui->action_Export_to_file);
accountMenu->addAction(d->ui->action_Import_from_file);
accountMenu->addSeparator();
accountMenu->addAction(d->ui->actionRe_load_Device_List);
accountMenu->addAction(d->ui->action_Remove_Device);
accountMenu->addSeparator();
accountMenu->addAction(d->ui->actionUpdate_Exchange_Key);
accountMenu->addSeparator();
accountMenu->addAction(d->ui->action_Change_Remote_Server);
accountMenu->addAction(d->ui->action_Reset_Identity);
d->ui->accountButton->setMenu(accountMenu);
//viewmodel stuff
connect(d->viewModel, &DataSyncViewModel::ready,
this, &DataSyncWindow::viewModelReady);
}
DataSyncWindow::~DataSyncWindow() {}
double DataSyncWindow::syncProgress() const
{
return d->ui->progressBar->value() / 1000.0;
}
QString DataSyncWindow::errorText() const
{
return d->ui->errorLabel->text();
}
void DataSyncWindow::setSyncProgress(double syncProgress)
{
if(syncProgress < 0)
d->ui->progressBar->reset();
else
d->ui->progressBar->setValue(static_cast<int>(syncProgress * 1000));
}
void DataSyncWindow::setErrorText(QString errorText)
{
d->ui->errorLabel->setText(errorText);
d->ui->stackedWidget->setCurrentIndex(errorText.isEmpty() ? 0 : 1);
}
void DataSyncWindow::viewModelReady()
{
//sync manager bindings
bind(d->viewModel->syncManager(), "syncEnabled",
d->ui->syncCheckBox, "checked");
bind(d->viewModel, "statusString",
d->ui->statusLabel, "text",
Binding::OneWayToView);
bind(d->viewModel->syncManager(), "syncProgress",
this, "syncProgress",
Binding::OneWayToView);
bind(d->viewModel->syncManager(), "lastError",
this, "errorText",
Binding::OneWayToView);
//account manager bindings
d->ui->treeView->setModel(d->viewModel->accountModel());
//sync manager connections
connect(d->ui->syncButton, &QCommandLinkButton::clicked,
d->viewModel, &DataSyncViewModel::syncOrConnect);
//account manager connections
connect(d->ui->actionEdit_Identity, &QAction::triggered,
d->viewModel, &DataSyncViewModel::showDeviceInfo);
connect(d->ui->action_Export_to_file, &QAction::triggered,
d->viewModel, &DataSyncViewModel::startExport);
connect(d->ui->action_Import_from_file, &QAction::triggered,
d->viewModel, &DataSyncViewModel::startImport);
connect(d->ui->action_Reset_Identity, &QAction::triggered,
d->viewModel, &DataSyncViewModel::performReset);
connect(d->ui->action_Change_Remote_Server, &QAction::triggered,
d->viewModel, &DataSyncViewModel::changeRemote);
connect(d->ui->action_Network_exchange, &QAction::triggered,
d->viewModel, &DataSyncViewModel::startNetworkExchange);
connect(d->ui->actionUpdate_Exchange_Key, &QAction::triggered,
d->viewModel->accountManager(), &AccountManager::updateExchangeKey);
connect(d->ui->actionRe_load_Device_List, &QAction::triggered,
d->viewModel->accountManager(), &AccountManager::listDevices);
connect(d->ui->action_Remove_Device, &QAction::triggered,
this, &DataSyncWindow::removeCurrentDevice);
connect(d->ui->actionUpdate_Exchange_Key, &QAction::triggered,
d->ui->actionUpdate_Exchange_Key, [this](){
d->ui->actionUpdate_Exchange_Key->setEnabled(false);
});
}
void DataSyncWindow::removeCurrentDevice()
{
auto index = d->ui->treeView->currentIndex();
if(index.isValid())
d->viewModel->accountModel()->removeDevice(index);
}
// ------------- Private Implementation -------------
DataSyncWindowPrivate::DataSyncWindowPrivate(DataSyncWindow *q_ptr, ViewModel *viewModel) :
DataSyncWindowPrivate::DataSyncWindowPrivate(ViewModel *viewModel) :
viewModel(static_cast<DataSyncViewModel*>(viewModel)),
ui(new Ui::DataSyncWindow())
{}

16
src/mvvmdatasyncwidgets/datasyncwindow.h

@ -16,10 +16,26 @@ class Q_MVVMDATASYNCWIDGETS_EXPORT DataSyncWindow : public QWidget
{
Q_OBJECT
Q_PROPERTY(double syncProgress READ syncProgress WRITE setSyncProgress)
Q_PROPERTY(QString errorText READ errorText WRITE setErrorText)
public:
Q_INVOKABLE explicit DataSyncWindow(QtMvvm::ViewModel *viewModel, QWidget *parent = nullptr);
~DataSyncWindow();
double syncProgress() const;
QString errorText() const;
public Q_SLOTS:
void setSyncProgress(double syncProgress);
void setErrorText(QString errorText);
protected Q_SLOTS:
virtual void viewModelReady();
private Q_SLOTS:
void removeCurrentDevice();
private:
QScopedPointer<DataSyncWindowPrivate> d;
};

316
src/mvvmdatasyncwidgets/datasyncwindow.ui

@ -1,21 +1,321 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<author/>
<comment/>
<exportmacro/>
<class>DataSyncWindow</class>
<widget name="DataSyncWindow" class="QWidget">
<widget class="QWidget" name="DataSyncWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<width>430</width>
<height>365</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>Synchronization</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0,1,0">
<item>
<widget class="QCheckBox" name="syncCheckBox">
<property name="text">
<string>Synchronization &amp;enabled</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
<item>
<widget class="QLabel" name="statusLabel">
<property name="font">
<font>
<pointsize>16</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QCommandLinkButton" name="syncButton">
<property name="text">
<string>&amp;Synchronize</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="progressPage">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="infoPage">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="errorLabel">
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>170</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>170</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="96">
<red>164</red>
<green>166</green>
<blue>168</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QTreeView" name="treeView">
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QToolButton" name="identityButton">
<property name="toolButtonStyle">
<enum>Qt::ToolButtonFollowStyle</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="accountButton">
<property name="text">
<string>Account &amp;actions</string>
</property>
<property name="icon">
<iconset theme="user-identity">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonFollowStyle</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
<action name="action_Import_from_file">
<property name="icon">
<iconset theme="document-import">
<normaloff>:/de/skycoder42/qtmvvm/datasync/widgets/icons/import.ico</normaloff>:/de/skycoder42/qtmvvm/datasync/widgets/icons/import.ico</iconset>
</property>
<property name="text">
<string>&amp;Import from file</string>
</property>
<property name="shortcut">
<string>Ctrl+I</string>
</property>
</action>
<action name="action_Export_to_file">
<property name="icon">
<iconset theme="document-export">
<normaloff>:/de/skycoder42/qtmvvm/datasync/widgets/icons/export.ico</normaloff>:/de/skycoder42/qtmvvm/datasync/widgets/icons/export.ico</iconset>
</property>
<property name="text">
<string>&amp;Export to file</string>
</property>
<property name="shortcut">
<string>Ctrl+E</string>
</property>
</action>
<action name="action_Network_exchange">
<property name="icon">
<iconset theme="network-connect">
<normaloff>:/de/skycoder42/qtmvvm/datasync/widgets/icons/exchange.ico</normaloff>:/de/skycoder42/qtmvvm/datasync/widgets/icons/exchange.ico</iconset>
</property>
<property name="text">
<string>&amp;Network exchange</string>
</property>
<property name="shortcut">
<string>Ctrl+N</string>
</property>
</action>
<action name="action_Reset_Identity">
<property name="icon">
<iconset theme="user-group-delete">
<normaloff>:/de/skycoder42/qtmvvm/datasync/widgets/icons/idreset.ico</normaloff>:/de/skycoder42/qtmvvm/datasync/widgets/icons/idreset.ico</iconset>
</property>
<property name="text">
<string>Rese&amp;t identity</string>
</property>
</action>
<action name="action_Change_Remote_Server">
<property name="icon">
<iconset theme="network-server">
<normaloff>:/de/skycoder42/qtmvvm/datasync/widgets/icons/changeRemote.ico</normaloff>:/de/skycoder42/qtmvvm/datasync/widgets/icons/changeRemote.ico</iconset>
</property>
<property name="text">
<string>&amp;Change remote server</string>
</property>
</action>
<action name="action_Remove_Device">
<property name="icon">
<iconset theme="list-remove">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Remove selected device</string>
</property>
<property name="shortcut">
<string>Del</string>
</property>
</action>
<action name="actionEdit_Identity">
<property name="icon">
<iconset theme="fingerprint-gui">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Identity</string>
</property>
<property name="shortcut">
<string>Ctrl+U</string>
</property>
</action>
<action name="actionUpdate_Exchange_Key">
<property name="icon">
<iconset theme="application-pgp-keys">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Update exchange &amp;key</string>
</property>
</action>
<action name="actionRe_load_Device_List">
<property name="icon">
<iconset theme="view-refresh">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Re&amp;load device list</string>
</property>
<property name="shortcut">
<string>Ctrl+R</string>
</property>
</action>
</widget>
<pixmapfunction/>
<resources/>
<connections/>
</ui>

2
src/mvvmdatasyncwidgets/datasyncwindow_p.h

@ -13,7 +13,7 @@ namespace QtMvvm {
class DataSyncWindowPrivate
{
public:
DataSyncWindowPrivate(DataSyncWindow *q_ptr, ViewModel *viewModel);
DataSyncWindowPrivate(ViewModel *viewModel);
DataSyncViewModel *viewModel;
QScopedPointer<Ui::DataSyncWindow> ui;

4
src/mvvmquick/quickpresenter.cpp

@ -106,7 +106,9 @@ void QuickPresenter::setInputViewFactory(InputViewFactory *inputViewFactory)
QUrl QuickPresenter::findViewUrl(const QMetaObject *viewModelType)
{
auto currentMeta = viewModelType;
while(currentMeta && currentMeta->inherits(&ViewModel::staticMetaObject)) {
while(currentMeta &&
currentMeta->inherits(&ViewModel::staticMetaObject) &&
currentMeta != &ViewModel::staticMetaObject) {
if(d->explicitMappings.contains(currentMeta))
return d->explicitMappings.value(currentMeta);
else {

26
src/mvvmwidgets/widgetspresenter.cpp

@ -132,19 +132,31 @@ void WidgetsPresenter::setInputWidgetFactory(InputWidgetFactory *inputWidgetFact
const QMetaObject *WidgetsPresenter::findWidgetMetaObject(const QMetaObject *viewModelMetaObject)
{
auto currentMeta = viewModelMetaObject;
while(currentMeta && currentMeta->inherits(&ViewModel::staticMetaObject)) {
while(currentMeta &&
currentMeta->inherits(&ViewModel::staticMetaObject) &&
currentMeta != &ViewModel::staticMetaObject) {
if(d->explicitMappings.contains(currentMeta))
return d->explicitMappings.value(currentMeta);
else {
QByteArray cName = currentMeta->className();
//strip viewmodel
auto lIndex = cName.lastIndexOf("ViewModel");
if(lIndex > 0)
cName.truncate(lIndex);
//strip namespaces
lIndex = cName.lastIndexOf("::");
if(lIndex > 0)
cName = cName.mid(lIndex + 2);
auto shortest = std::numeric_limits<int>::max();
const QMetaObject *res = nullptr;
for(auto metaObject : d->implicitMappings) {
QByteArray vName = metaObject->className();
//strip namespaces
lIndex = vName.lastIndexOf("::");
if(lIndex > 0)
vName = vName.mid(lIndex + 2);
if(vName.startsWith(cName) && vName.size() < shortest) {
shortest = vName.size();
res = metaObject;
@ -390,13 +402,13 @@ void WidgetsPresenter::presentFileDialog(const MessageConfig &config, QPointer<M
QObject::connect(dialog, &QDialog::finished,
dialog, [dialog, isMultiFile, result](int resCode){
if(result) {
if(isMultiFile)
result->setResult(QVariant::fromValue(dialog->selectedUrls()));
else
result->setResult(dialog->selectedUrls().first());
if(resCode == QDialog::Accepted)
if(resCode == QDialog::Accepted) {
if(isMultiFile)
result->setResult(QVariant::fromValue(dialog->selectedUrls()));
else if(!dialog->selectedUrls().isEmpty())
result->setResult(dialog->selectedUrls().first());
result->complete(MessageConfig::Ok);
else
} else
result->complete(MessageConfig::Cancel);
}
});

Loading…
Cancel
Save