Compare commits
59 Commits
641cf02db4
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| 6408eaa10a | |||
| 24192df5d6 | |||
| c7b0e4f3e5 | |||
| 7fa8612313 | |||
| 8dbceabb8a | |||
| 2d8c97b5f0 | |||
| 2fb7560e6e | |||
| 560cadb2c0 | |||
| 0e7f803d42 | |||
| d56af7231c | |||
| 385dc7ca76 | |||
| 5e3950f6ba | |||
| 34a34891b4 | |||
| 4c4d734b1b | |||
| 0eef55fc32 | |||
| d109eb31f8 | |||
| a9f24ac8f2 | |||
| 67d9a3914d | |||
| 518bebcbb7 | |||
| 8f61c6bc2f | |||
| a966b26185 | |||
| a8bf5b4032 | |||
| c83ba2da9d | |||
| 232b9ceb78 | |||
| e915846b8a | |||
| 8a0d37f8f9 | |||
| bd056a00ce | |||
| 5eee7a4a75 | |||
| 3cab6d6b86 | |||
| 78a55b6559 | |||
| 683f5d224c | |||
| bcba8f8452 | |||
| 12e5596b34 | |||
| 8333be2044 | |||
| 6cd0519237 | |||
| d94a928fc0 | |||
| fd7e0975f5 | |||
| b3f83ccdb0 | |||
| 8d523bb5bc | |||
| 467ab58fae | |||
| 47338e5ae2 | |||
| 902ed1c84b | |||
| ec0d72953f | |||
| c80a692a28 | |||
| c51c06ba50 | |||
| ea75e57dbf | |||
| 928b795f4e | |||
| 370bcd5a41 | |||
| c7012ceff5 | |||
| 5e54f52cd6 | |||
| 64a65b5916 | |||
| 9a30fb2aad | |||
| 8105fac8d3 | |||
| 7dd9d3d95b | |||
| c8825bfe14 | |||
| 43df76c88f | |||
| dd8847d63a | |||
| f359a1fb11 | |||
| 9c67fdabdc |
@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
set(TARGET_APP "GenericWidgets")
|
set(TARGET_APP "GenericQtClient-Widgets")
|
||||||
project(${TARGET_APP} VERSION 0.0.1 LANGUAGES CXX)
|
project(${TARGET_APP} VERSION 0.3.0 LANGUAGES CXX)
|
||||||
|
|
||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
@ -27,15 +27,24 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
|||||||
qt_add_executable(${TARGET_APP}
|
qt_add_executable(${TARGET_APP}
|
||||||
MANUAL_FINALIZATION
|
MANUAL_FINALIZATION
|
||||||
${PROJECT_SOURCES}
|
${PROJECT_SOURCES}
|
||||||
utils/messagehandler.h
|
|
||||||
assets/icons.qrc
|
assets/icons.qrc
|
||||||
|
dialogs/abstractdialog.h dialogs/abstractdialog.cpp
|
||||||
|
dialogs/newitemdialog.h dialogs/newitemdialog.cpp
|
||||||
|
dialogs/edititemdialog.h dialogs/edititemdialog.cpp
|
||||||
|
dialogs/settingsdialog.h dialogs/settingsdialog.cpp
|
||||||
|
views/itemdetailmapper.h views/itemdetailmapper.cpp
|
||||||
|
widgets/controls/comboboxdelegate.h widgets/controls/comboboxdelegate.cpp
|
||||||
|
widgethelper.h widgethelper.cpp
|
||||||
|
widgets/controls/spinboxdelegate.h widgets/controls/spinboxdelegate.cpp
|
||||||
)
|
)
|
||||||
# Define target properties for Android with Qt 6 as:
|
# Define target properties for Android with Qt 6 as:
|
||||||
# set_property(TARGET ${TARGET_APP} APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
|
# set_property(TARGET ${TARGET_APP} APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
|
||||||
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
|
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
|
||||||
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
|
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
|
||||||
|
|
||||||
qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
|
# qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
|
||||||
|
|
||||||
else()
|
else()
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
add_library(${TARGET_APP} SHARED
|
add_library(${TARGET_APP} SHARED
|
||||||
@ -52,10 +61,14 @@ endif()
|
|||||||
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
|
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
target_link_libraries(${TARGET_APP} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
|
target_link_libraries(${TARGET_APP} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
|
||||||
|
|
||||||
target_include_directories(${TARGET_APP} PRIVATE ${CORE_LIB_DIR}/)
|
target_include_directories(${TARGET_APP} PRIVATE ${CORE_LIB_DIR}/)
|
||||||
target_link_libraries(${TARGET_APP} PRIVATE GenericCore)
|
target_link_libraries(${TARGET_APP} PRIVATE GenericCore)
|
||||||
|
target_include_directories(${TARGET_APP} PRIVATE ${QR_LIB_DIR}/src)
|
||||||
|
target_link_libraries(${TARGET_APP} PRIVATE qrcode)
|
||||||
|
|
||||||
|
|
||||||
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
@ -1,7 +1,6 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>software-application.png</file>
|
<file>software-application.png</file>
|
||||||
<file>feature.png</file>
|
|
||||||
<file>no-picture-taking.png</file>
|
<file>no-picture-taking.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 22 KiB |
51
dialogs/abstractdialog.cpp
Normal file
51
dialogs/abstractdialog.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "abstractdialog.h"
|
||||||
|
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
AbstractDialog::AbstractDialog(QDialogButtonBox::StandardButtons buttons, QWidget* parent)
|
||||||
|
: QDialog(parent) {
|
||||||
|
setWindowTitle(tr("Dialog does what?..."));
|
||||||
|
setModal(true);
|
||||||
|
|
||||||
|
m_buttonBox = new QDialogButtonBox(buttons, this);
|
||||||
|
connect(m_buttonBox, &QDialogButtonBox::accepted, this, &AbstractDialog::accept);
|
||||||
|
connect(m_buttonBox, &QDialogButtonBox::rejected, this, &AbstractDialog::reject);
|
||||||
|
|
||||||
|
m_contentContainer = new QLabel("content", this);
|
||||||
|
|
||||||
|
m_outerLayout = new QVBoxLayout;
|
||||||
|
m_outerLayout->addWidget(m_contentContainer);
|
||||||
|
m_outerLayout->addWidget(m_buttonBox);
|
||||||
|
|
||||||
|
setLayout(m_outerLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractDialog::show() {
|
||||||
|
centerInParent();
|
||||||
|
QWidget::show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractDialog::accept() { QDialog::accept(); }
|
||||||
|
|
||||||
|
void AbstractDialog::reject() { QDialog::reject(); }
|
||||||
|
|
||||||
|
void AbstractDialog::centerInParent() {
|
||||||
|
// BUG the centering in the parent doesn't work the first time (and the later ones seem off too)
|
||||||
|
QWidget* parent = parentWidget();
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
auto parentRect = parent->geometry();
|
||||||
|
move(parentRect.center() - rect().center());
|
||||||
|
} else {
|
||||||
|
QRect screenGeometry = QGuiApplication::screens().at(0)->geometry();
|
||||||
|
int x = (screenGeometry.width() - width()) / 2;
|
||||||
|
int y = (screenGeometry.height() - height()) / 2;
|
||||||
|
move(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractDialog::closeEvent(QCloseEvent* event) { QWidget::closeEvent(event); }
|
||||||
33
dialogs/abstractdialog.h
Normal file
33
dialogs/abstractdialog.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef ABSTRACTDIALOG_H
|
||||||
|
#define ABSTRACTDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
|
||||||
|
class QGridLayout;
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
|
class AbstractDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
AbstractDialog(QDialogButtonBox::StandardButtons buttons, QWidget* parent = nullptr);
|
||||||
|
virtual void createContent() = 0;
|
||||||
|
|
||||||
|
/// QDialog interface
|
||||||
|
public slots:
|
||||||
|
void show();
|
||||||
|
void accept() override;
|
||||||
|
void reject() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void centerInParent();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QWidget* m_contentContainer;
|
||||||
|
QVBoxLayout* m_outerLayout;
|
||||||
|
QDialogButtonBox* m_buttonBox = nullptr;
|
||||||
|
|
||||||
|
void closeEvent(QCloseEvent* event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ABSTRACTDIALOG_H
|
||||||
56
dialogs/edititemdialog.cpp
Normal file
56
dialogs/edititemdialog.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "edititemdialog.h"
|
||||||
|
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include "../views/itemdetailmapper.h"
|
||||||
|
|
||||||
|
EditItemDialog::EditItemDialog(QTableView* tableView, QWidget* parent)
|
||||||
|
: AbstractDialog(QDialogButtonBox::Ok, parent)
|
||||||
|
, m_tableView(tableView)
|
||||||
|
, m_qrCodeDisplay(new QLabel("QR Code")) {}
|
||||||
|
|
||||||
|
void EditItemDialog::createContent() {
|
||||||
|
if (m_contentContainer) {
|
||||||
|
delete m_contentContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
setWindowTitle(tr("Edit item..."));
|
||||||
|
|
||||||
|
m_contentContainer = new QWidget(this);
|
||||||
|
QHBoxLayout* innerLayout = new QHBoxLayout();
|
||||||
|
m_contentContainer->setLayout(innerLayout);
|
||||||
|
|
||||||
|
m_detailMapper = new ItemDetailMapper(m_tableView, this);
|
||||||
|
innerLayout->addWidget(m_detailMapper);
|
||||||
|
|
||||||
|
updateQRCode();
|
||||||
|
connect(m_detailMapper, &ItemDetailMapper::contentChanged, this, &EditItemDialog::updateQRCode);
|
||||||
|
innerLayout->addWidget(m_qrCodeDisplay);
|
||||||
|
|
||||||
|
m_outerLayout->insertWidget(0, m_contentContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditItemDialog::accept() {
|
||||||
|
m_detailMapper->submit();
|
||||||
|
QDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditItemDialog::reject() {
|
||||||
|
m_detailMapper->revert();
|
||||||
|
QDialog::reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditItemDialog::updateQRCode(const QString text) {
|
||||||
|
QImage unscaledImage;
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
unscaledImage = QImage("://no-picture-taking.png");
|
||||||
|
} else {
|
||||||
|
unscaledImage = m_generator.generateQr(text);
|
||||||
|
}
|
||||||
|
QImage image = unscaledImage.scaled(250, 250);
|
||||||
|
|
||||||
|
m_qrCodeDisplay->setPixmap(QPixmap::fromImage(image));
|
||||||
|
m_qrCodeDisplay->setToolTip(text);
|
||||||
|
}
|
||||||
53
dialogs/edititemdialog.h
Normal file
53
dialogs/edititemdialog.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef EDITITEMDIALOG_H
|
||||||
|
#define EDITITEMDIALOG_H
|
||||||
|
|
||||||
|
#include "QrCodeGenerator.h"
|
||||||
|
#include "abstractdialog.h"
|
||||||
|
|
||||||
|
class QDoubleSpinBox;
|
||||||
|
class QLineEdit;
|
||||||
|
class QSpinBox;
|
||||||
|
class QLabel;
|
||||||
|
class QTableView;
|
||||||
|
|
||||||
|
class ItemDetailMapper;
|
||||||
|
|
||||||
|
class EditItemDialog : public AbstractDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
EditItemDialog(QTableView* tableView, QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
/// AbstractDialog interface
|
||||||
|
void createContent() override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void accept() override;
|
||||||
|
void reject() override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateQRCode(const QString text = "");
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTableView* m_tableView = nullptr;
|
||||||
|
ItemDetailMapper* m_detailMapper;
|
||||||
|
|
||||||
|
QLabel* m_nameLabel = nullptr;
|
||||||
|
QLineEdit* m_nameEdit = nullptr;
|
||||||
|
|
||||||
|
QLabel* m_descriptionLabel = nullptr;
|
||||||
|
QLineEdit* m_descriptionEdit = nullptr;
|
||||||
|
|
||||||
|
QLabel* m_infoLabel = nullptr;
|
||||||
|
QLineEdit* m_infoEdit = nullptr;
|
||||||
|
|
||||||
|
QLabel* m_amountLabel = nullptr;
|
||||||
|
QSpinBox* m_amountBox = nullptr;
|
||||||
|
|
||||||
|
QLabel* m_factorLabel = nullptr;
|
||||||
|
QDoubleSpinBox* m_factorBox = nullptr;
|
||||||
|
|
||||||
|
QLabel* m_qrCodeDisplay = nullptr;
|
||||||
|
QrCodeGenerator m_generator;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EDITITEMDIALOG_H
|
||||||
108
dialogs/newitemdialog.cpp
Normal file
108
dialogs/newitemdialog.cpp
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#include "newitemdialog.h"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QStringListModel>
|
||||||
|
|
||||||
|
#include "../widgethelper.h"
|
||||||
|
#include "formats/jsonparser.h"
|
||||||
|
#include "model/metadata.h"
|
||||||
|
|
||||||
|
NewItemDialog::NewItemDialog(QWidget* parent)
|
||||||
|
: AbstractDialog(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, parent) {}
|
||||||
|
|
||||||
|
void NewItemDialog::createContent() {
|
||||||
|
if (m_contentContainer) {
|
||||||
|
delete m_contentContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
setWindowTitle(tr("New item..."));
|
||||||
|
|
||||||
|
m_contentContainer = new QWidget(this);
|
||||||
|
|
||||||
|
m_layout = new QGridLayout();
|
||||||
|
|
||||||
|
for (int i = 0; i < USER_FACING_ROLES.size(); ++i) {
|
||||||
|
setupWidgetPairForColumn(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_contentContainer->setLayout(m_layout);
|
||||||
|
|
||||||
|
m_outerLayout->insertWidget(0, m_contentContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewItemDialog::accept() {
|
||||||
|
addItemToModel();
|
||||||
|
|
||||||
|
resetContent();
|
||||||
|
|
||||||
|
AbstractDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewItemDialog::setupWidgetPairForColumn(const int column) {
|
||||||
|
// REFACTOR consolidate NewItemDialog::setupWidgetPairForColumn(...)
|
||||||
|
// with ItemDetailMapper::setupWidgetPairForColumn(...)
|
||||||
|
const UserRoles role = GET_ROLE_FOR_COLUMN(column);
|
||||||
|
|
||||||
|
QWidget* control = WidgetHelper::createControlWidget(role, this);
|
||||||
|
|
||||||
|
const QString string = QString("&%1").arg(GET_HEADER_FOR_COLUMN(column));
|
||||||
|
QLabel* label = new QLabel(string);
|
||||||
|
label->setBuddy(control);
|
||||||
|
|
||||||
|
m_layout->addWidget(label, column, 0);
|
||||||
|
m_layout->addWidget(control, column, 1);
|
||||||
|
m_controlWidgets.append(control);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewItemDialog::addItemToModel() {
|
||||||
|
ModelItemValues itemValues;
|
||||||
|
|
||||||
|
for (int i = 0; i < m_controlWidgets.size(); ++i) {
|
||||||
|
const UserRoles role = GET_ROLE_FOR_COLUMN(i);
|
||||||
|
if (STRING_ROLES.contains(role)) {
|
||||||
|
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(m_controlWidgets[i]);
|
||||||
|
itemValues.insert(role, lineEdit->text());
|
||||||
|
} else if (TYPE_ROLES.contains(role)) {
|
||||||
|
QComboBox* comboBox = dynamic_cast<QComboBox*>(m_controlWidgets[i]);
|
||||||
|
itemValues.insert(role, comboBox->currentText());
|
||||||
|
} else if (INT_ROLES.contains(role)) {
|
||||||
|
QSpinBox* spinBox = dynamic_cast<QSpinBox*>(m_controlWidgets[i]);
|
||||||
|
itemValues.insert(role, spinBox->value());
|
||||||
|
} else if (DOUBLE_ROLES.contains(role)) {
|
||||||
|
QDoubleSpinBox* doubleSpinBox = dynamic_cast<QDoubleSpinBox*>(m_controlWidgets[i]);
|
||||||
|
itemValues.insert(role, doubleSpinBox->value());
|
||||||
|
} else {
|
||||||
|
qCritical() << "Could not reset content for control widget in column:" << i << "!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray jsonDoc = JsonParser::itemValuesListToJson({itemValues}, ITEMS_KEY_STRING);
|
||||||
|
emit addItems(jsonDoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewItemDialog::resetContent() {
|
||||||
|
for (int i = 0; i < m_controlWidgets.size(); ++i) {
|
||||||
|
const UserRoles role = GET_ROLE_FOR_COLUMN(i);
|
||||||
|
if (STRING_ROLES.contains(role)) {
|
||||||
|
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(m_controlWidgets[i]);
|
||||||
|
lineEdit->clear();
|
||||||
|
} else if (TYPE_ROLES.contains(role)) {
|
||||||
|
QComboBox* comboBox = dynamic_cast<QComboBox*>(m_controlWidgets[i]);
|
||||||
|
comboBox->setCurrentText("");
|
||||||
|
} else if (INT_ROLES.contains(role)) {
|
||||||
|
QSpinBox* spinBox = dynamic_cast<QSpinBox*>(m_controlWidgets[i]);
|
||||||
|
spinBox->setValue(0);
|
||||||
|
} else if (DOUBLE_ROLES.contains(role)) {
|
||||||
|
QDoubleSpinBox* doubleSpinBox = dynamic_cast<QDoubleSpinBox*>(m_controlWidgets[i]);
|
||||||
|
doubleSpinBox->setValue(0.0);
|
||||||
|
} else {
|
||||||
|
qCritical() << "Could not reset content for control widget in column:" << i << "!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
dialogs/newitemdialog.h
Normal file
36
dialogs/newitemdialog.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef NEWITEMDIALOG_H
|
||||||
|
#define NEWITEMDIALOG_H
|
||||||
|
|
||||||
|
#include "abstractdialog.h"
|
||||||
|
|
||||||
|
class QDoubleSpinBox;
|
||||||
|
class QLineEdit;
|
||||||
|
class QSpinBox;
|
||||||
|
class QLabel;
|
||||||
|
|
||||||
|
class NewItemDialog : public AbstractDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
NewItemDialog(QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
void createContent() override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void addItems(const QByteArray& jsonDoc);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void accept() override;
|
||||||
|
// void reject() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QGridLayout* m_layout;
|
||||||
|
QList<QWidget*> m_controlWidgets;
|
||||||
|
|
||||||
|
void setupWidgetPairForColumn(const int column);
|
||||||
|
|
||||||
|
void addItemToModel();
|
||||||
|
void resetContent();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NEWITEMDIALOG_H
|
||||||
63
dialogs/settingsdialog.cpp
Normal file
63
dialogs/settingsdialog.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include "settingsdialog.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QTabWidget>
|
||||||
|
|
||||||
|
SettingsDialog::SettingsDialog(QWidget* parent)
|
||||||
|
: AbstractDialog(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, parent) {}
|
||||||
|
|
||||||
|
void SettingsDialog::createContent() {
|
||||||
|
if (m_contentContainer) {
|
||||||
|
delete m_contentContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString dialogTitle = tr("Settings - ");
|
||||||
|
const QString applicationName = QCoreApplication::applicationName();
|
||||||
|
|
||||||
|
setWindowTitle(dialogTitle + applicationName);
|
||||||
|
setModal(true);
|
||||||
|
setGeometry(0, 0, 350, 250);
|
||||||
|
QGridLayout* serverLayout = new QGridLayout();
|
||||||
|
QLabel* urlLabel = new QLabel("Server URL:");
|
||||||
|
m_urlEdit = new QLineEdit();
|
||||||
|
serverLayout->addWidget(urlLabel, 0, 0);
|
||||||
|
serverLayout->addWidget(m_urlEdit, 0, 1);
|
||||||
|
QLabel* emailLabel = new QLabel("Email:");
|
||||||
|
m_emailEdit = new QLineEdit();
|
||||||
|
m_emailEdit->setEnabled(false);
|
||||||
|
serverLayout->addWidget(emailLabel, 1, 0);
|
||||||
|
serverLayout->addWidget(m_emailEdit, 1, 1);
|
||||||
|
QLabel* passwordLabel = new QLabel("Password:");
|
||||||
|
m_passwordEdit = new QLineEdit();
|
||||||
|
m_passwordEdit->setEnabled(false);
|
||||||
|
m_passwordEdit->setEchoMode(QLineEdit::Password);
|
||||||
|
serverLayout->addWidget(passwordLabel, 2, 0);
|
||||||
|
serverLayout->addWidget(m_passwordEdit, 2, 1);
|
||||||
|
|
||||||
|
QWidget* serverTab = new QWidget();
|
||||||
|
serverTab->setLayout(serverLayout);
|
||||||
|
|
||||||
|
QTabWidget* widget = new QTabWidget();
|
||||||
|
widget->addTab(serverTab, "Server");
|
||||||
|
|
||||||
|
m_contentContainer = widget;
|
||||||
|
m_outerLayout->insertWidget(0, m_contentContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsDialog::fillContent(const QVariantMap& settings) {
|
||||||
|
m_urlEdit->setText(settings.value("url").toString());
|
||||||
|
m_emailEdit->setText(settings.value("email").toString());
|
||||||
|
m_passwordEdit->setText(settings.value("password").toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap SettingsDialog::getSettings() const {
|
||||||
|
QVariantMap result;
|
||||||
|
result.insert("url", m_urlEdit->text());
|
||||||
|
result.insert("email", m_emailEdit->text());
|
||||||
|
result.insert("password", m_passwordEdit->text());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
23
dialogs/settingsdialog.h
Normal file
23
dialogs/settingsdialog.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef SETTINGSDIALOG_H
|
||||||
|
#define SETTINGSDIALOG_H
|
||||||
|
|
||||||
|
#include "abstractdialog.h"
|
||||||
|
|
||||||
|
class QLineEdit;
|
||||||
|
|
||||||
|
class SettingsDialog : public AbstractDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SettingsDialog(QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
void createContent() override;
|
||||||
|
void fillContent(const QVariantMap& settings);
|
||||||
|
QVariantMap getSettings() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLineEdit* m_urlEdit = nullptr;
|
||||||
|
QLineEdit* m_emailEdit = nullptr;
|
||||||
|
QLineEdit* m_passwordEdit = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SETTINGSDIALOG_H
|
||||||
540
mainwindow.cpp
540
mainwindow.cpp
@ -1,31 +1,565 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "./ui_mainwindow.h"
|
#include "./ui_mainwindow.h"
|
||||||
|
|
||||||
#include "../../libs/GenericCore/genericcore.h"
|
#include <QCloseEvent>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QUndoStack>
|
||||||
|
#include <QUndoView>
|
||||||
|
|
||||||
|
#include "../../ApplicationConfig.h"
|
||||||
|
#include "dialogs/edititemdialog.h"
|
||||||
|
#include "dialogs/newitemdialog.h"
|
||||||
|
#include "dialogs/settingsdialog.h"
|
||||||
|
#include "genericcore.h"
|
||||||
|
#include "model/generalsortfiltermodel.h"
|
||||||
|
#include "model/metadata.h"
|
||||||
|
#include "model/tablemodel.h"
|
||||||
|
#include "widgets/controls/comboboxdelegate.h"
|
||||||
|
#include "widgets/controls/spinboxdelegate.h"
|
||||||
|
|
||||||
|
static QStandardPaths::StandardLocation standardLocation = QStandardPaths::HomeLocation;
|
||||||
|
static QString updateTextClean = "Do you want to update the application now?";
|
||||||
|
static QString updateTextDirty = "Do you want to save the tasks & update the application now?";
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget* parent)
|
MainWindow::MainWindow(QWidget* parent)
|
||||||
: QMainWindow(parent)
|
: QMainWindow(parent)
|
||||||
, ui(new Ui::MainWindow) {
|
, ui(new Ui::MainWindow) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
m_core = std::make_shared<GenericCore>();
|
m_core = std::make_unique<GenericCore>();
|
||||||
|
|
||||||
|
setWindowTitle(QCoreApplication::applicationName() + " [*]");
|
||||||
|
|
||||||
/// application icon
|
/// application icon
|
||||||
const QString iconString = "://feature.png";
|
const QString iconString = "://software-application.png";
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
QPixmap pixmap = QPixmap(iconString);
|
QPixmap pixmap = QPixmap(iconString);
|
||||||
QTransform transform = QTransform();
|
QTransform transform = QTransform();
|
||||||
transform.rotate(180);
|
transform.rotate(180);
|
||||||
QPixmap rotated = pixmap.transformed(transform);
|
QPixmap rotated = pixmap.transformed(transform);
|
||||||
|
QIcon appIcon = QIcon(rotated);
|
||||||
setWindowIcon(QIcon(rotated));
|
setWindowIcon(QIcon(rotated));
|
||||||
#else
|
#else
|
||||||
setWindowIcon(QIcon(iconString));
|
setWindowIcon(QIcon(iconString));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const QVariantMap settings = m_core->getSettings("GUI");
|
||||||
|
restoreGeometry(settings.value("geometry").toByteArray());
|
||||||
|
restoreState(settings.value("windowState").toByteArray());
|
||||||
|
|
||||||
|
setupModelViews();
|
||||||
|
|
||||||
|
createActions();
|
||||||
|
createHelpMenu();
|
||||||
|
createGuiDialogs();
|
||||||
|
|
||||||
|
connect(m_core.get(), &GenericCore::displayStatusMessage, this,
|
||||||
|
&MainWindow::displayStatusMessage);
|
||||||
|
connect(this, &MainWindow::displayStatusMessage, this, &MainWindow::showStatusMessage);
|
||||||
|
connect(this, &MainWindow::checkForUpdates, this,
|
||||||
|
&MainWindow::on_actionCheck_for_update_triggered, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
// connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
||||||
|
// &MainWindow::onSelectionChanged);
|
||||||
|
connect(ui->tableView->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
||||||
|
&MainWindow::onCurrentChanged);
|
||||||
|
|
||||||
|
onSelectionChanged(QItemSelection(), QItemSelection());
|
||||||
|
onCurrentChanged(QModelIndex(), QModelIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow() { delete ui; }
|
MainWindow::~MainWindow() { delete ui; }
|
||||||
|
|
||||||
|
void MainWindow::closeEvent(QCloseEvent* event) {
|
||||||
|
if (isWindowModified()) {
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setWindowTitle(windowTitle() + " - Save dialog");
|
||||||
|
msgBox.setText("The document has been modified.");
|
||||||
|
msgBox.setInformativeText("Do you want to save your changes?");
|
||||||
|
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||||
|
msgBox.setDefaultButton(QMessageBox::Save);
|
||||||
|
int ret = msgBox.exec();
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case QMessageBox::Save:
|
||||||
|
emit saveItems();
|
||||||
|
event->accept();
|
||||||
|
break;
|
||||||
|
case QMessageBox::Discard:
|
||||||
|
event->accept();
|
||||||
|
break;
|
||||||
|
case QMessageBox::Cancel:
|
||||||
|
event->ignore();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/// should never be reached
|
||||||
|
qCritical() << "unexpected switch case in closeEvent:" << ret;
|
||||||
|
event->ignore();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->isAccepted()) {
|
||||||
|
qInfo() << "Saving GUI settings...";
|
||||||
|
m_core->applySettings({{"geometry", saveGeometry()}, {"windowState", saveState()}}, "GUI");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::showStatusMessage(const QString text) {
|
||||||
|
qInfo() << text;
|
||||||
|
ui->statusbar->showMessage(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onCurrentChanged(const QModelIndex& current, const QModelIndex& previous) {
|
||||||
|
// Q_UNUSED(current);
|
||||||
|
Q_UNUSED(previous);
|
||||||
|
|
||||||
|
// QItemSelection localSelection = ui->tableView->selectionModel()->selection();
|
||||||
|
if (current == QModelIndex()) {
|
||||||
|
// qDebug() << "Nothing selected. Disabling delete action";
|
||||||
|
m_deleteItemAct->setEnabled(false);
|
||||||
|
} else {
|
||||||
|
// qDebug() << "Something selected. Enabling delete action";
|
||||||
|
m_deleteItemAct->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onSelectionChanged(const QItemSelection& selected,
|
||||||
|
const QItemSelection& deselected) {
|
||||||
|
Q_UNUSED(selected);
|
||||||
|
Q_UNUSED(deselected);
|
||||||
|
|
||||||
|
QItemSelection localSelection = ui->tableView->selectionModel()->selection();
|
||||||
|
if (localSelection.empty()) {
|
||||||
|
// qDebug() << "Nothing selected. Disabling delete action";
|
||||||
|
m_deleteItemAct->setEnabled(false);
|
||||||
|
} else {
|
||||||
|
// qDebug() << "Something selected. Enabling delete action";
|
||||||
|
m_deleteItemAct->setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onAboutClicked() {
|
||||||
|
const QString applicationName = APPLICATION_NAME;
|
||||||
|
const QString titlePrefix = tr("About ");
|
||||||
|
const QString aboutText =
|
||||||
|
tr(QString("<b>%1 v%2</b> is a template for Qt applications."
|
||||||
|
"<br><br><a href=\"https://working-copy.org/\">Working-Copy_Collective website</a>"
|
||||||
|
"<br><br><a href=\"mailto:support@working-copy.org\">Mail to support</a>"
|
||||||
|
"<br><br>It uses the <a href=\"https://qt.io\">Qt Framework</a>.")
|
||||||
|
.arg(applicationName)
|
||||||
|
.arg(APPLICATION_VERSION)
|
||||||
|
.toLatin1());
|
||||||
|
QMessageBox::about(this, titlePrefix + applicationName, aboutText);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionCheck_for_update_triggered() {
|
||||||
|
showStatusMessage("Checking for update...");
|
||||||
|
const bool updateAvailable = m_core->isApplicationUpdateAvailable();
|
||||||
|
if (updateAvailable) {
|
||||||
|
const QString text = isWindowModified() ? updateTextDirty : updateTextClean;
|
||||||
|
const QMessageBox::StandardButton clickedButton = QMessageBox::question(
|
||||||
|
this, tr("Update available."), text, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
|
if (clickedButton == QMessageBox::Yes) {
|
||||||
|
m_core->triggerApplicationUpdate(true);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_pushButton_clicked() {
|
void MainWindow::on_pushButton_clicked() {
|
||||||
const QString prefix("Backend provided by: ");
|
const QString prefix("Backend provided by: ");
|
||||||
ui->label->setText(prefix + m_core->toString());
|
ui->label->setText(prefix + m_core->toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::openNewItemDialog() {
|
||||||
|
showStatusMessage(tr("Invoked 'Edit|New Item'"));
|
||||||
|
m_newItemDialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::openEditItemDialog() {
|
||||||
|
showStatusMessage(tr("Invoked 'Edit|Edit Item'"));
|
||||||
|
m_editItemDialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::deleteCurrentItem() {
|
||||||
|
showStatusMessage(tr("Invoked 'Edit|Delete Item'"));
|
||||||
|
// QItemSelection localSelection = ui->tableView->selectionModel()->selection();
|
||||||
|
const QModelIndex currentIndex = ui->tableView->selectionModel()->currentIndex();
|
||||||
|
if (currentIndex == QModelIndex()) {
|
||||||
|
qDebug() << "No current item. Nothing to remove.";
|
||||||
|
} else {
|
||||||
|
m_proxyModel->removeRows(currentIndex.row(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::deleteSelectedtItems() {
|
||||||
|
showStatusMessage(tr("Invoked 'Edit|Delete Item'"));
|
||||||
|
QItemSelection localSelection = ui->tableView->selectionModel()->selection();
|
||||||
|
if (localSelection.empty()) {
|
||||||
|
qDebug() << "No items selected. Nothing to remove.";
|
||||||
|
} else {
|
||||||
|
for (QList<QItemSelectionRange>::reverse_iterator iter = localSelection.rbegin(),
|
||||||
|
rend = localSelection.rend();
|
||||||
|
iter != rend; ++iter) {
|
||||||
|
// qInfo() << "iter:" << *iter;
|
||||||
|
// const QModelIndex parentIndex = iter->parent();
|
||||||
|
const int topRow = iter->top();
|
||||||
|
const int bottomRow = iter->bottom();
|
||||||
|
const int nRows = bottomRow - topRow + 1;
|
||||||
|
m_proxyModel->removeRows(topRow, nRows);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onCleanStateChanged(bool clean) {
|
||||||
|
qInfo() << "Slot onCleanStateChanged triggered: clean:" << clean;
|
||||||
|
setWindowModified(!clean);
|
||||||
|
if (!clean) {
|
||||||
|
ui->statusbar->clearMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onShowUndoViewToggled(bool checked) {
|
||||||
|
// qInfo() << "Slot onShowUndoViewToggled toggled: checked:" << checked;
|
||||||
|
// m_undoView->setVisible(checked);
|
||||||
|
|
||||||
|
/// workaround until m_showUndoViewAction is checkable
|
||||||
|
qInfo() << "Slot onShowUndoViewToggled triggered, toggleing undo view...";
|
||||||
|
Q_UNUSED(checked);
|
||||||
|
if (m_modelUndoView->isVisible()) {
|
||||||
|
m_modelUndoView->setVisible(false);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
m_modelUndoView->setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::saveItems() {
|
||||||
|
showStatusMessage(tr("Invoked 'File|Save'"));
|
||||||
|
m_core->saveItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::importCSV() {
|
||||||
|
showStatusMessage(tr("Invoked 'File|Import CSV'"));
|
||||||
|
const QString csvFilePath = QFileDialog::getOpenFileName(
|
||||||
|
this, tr("Import CSV"), QStandardPaths::standardLocations(standardLocation).first(),
|
||||||
|
tr("CSV Files (*.csv)"));
|
||||||
|
if (QFileInfo::exists(csvFilePath)) {
|
||||||
|
m_core->importCSVFile(csvFilePath);
|
||||||
|
} else {
|
||||||
|
qWarning() << "Selected CSV file path doesn't exist. Doing nothing...";
|
||||||
|
showStatusMessage(tr("Could't find CSV file!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::exportCSV() {
|
||||||
|
showStatusMessage(tr("Invoked 'File|Export'"));
|
||||||
|
const QString filter = tr("CSV Files (*.csv)");
|
||||||
|
const QString location = QStandardPaths::standardLocations(standardLocation).first();
|
||||||
|
QFileDialog dialog(this, "Export CSV File", location, "Comma-separated file (*.csv)");
|
||||||
|
dialog.setDefaultSuffix(".csv");
|
||||||
|
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||||
|
if (dialog.exec()) {
|
||||||
|
const QString csvFilePath = dialog.selectedFiles().first();
|
||||||
|
const bool successful = m_core->exportCSVFile(csvFilePath);
|
||||||
|
if (successful) {
|
||||||
|
const QString message = QString(tr("CSV exported to: %1")).arg(csvFilePath);
|
||||||
|
showStatusMessage(message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qWarning() << "Selected CSV file path doesn't exist. Doing nothing...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::findItems() {
|
||||||
|
showStatusMessage(tr("Invoked 'Edit|Find items'"));
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
QString text = QInputDialog::getText(this, tr("Find items"), tr("Enter the text to search for:"),
|
||||||
|
QLineEdit::Normal, "", &ok);
|
||||||
|
if (ok && !text.isEmpty()) {
|
||||||
|
const QItemSelection itemsToSelect = m_proxyModel->findItems(text);
|
||||||
|
if (itemsToSelect.empty()) {
|
||||||
|
ui->tableView->setCurrentIndex(QModelIndex());
|
||||||
|
ui->tableView->selectionModel()->select(QModelIndex(), QItemSelectionModel::ClearAndSelect);
|
||||||
|
} else {
|
||||||
|
ui->tableView->setCurrentIndex(itemsToSelect.first().topLeft());
|
||||||
|
ui->tableView->selectionModel()->select(itemsToSelect, QItemSelectionModel::ClearAndSelect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::fetchItems() {
|
||||||
|
showStatusMessage(tr("Invoked 'Server|Fetch items'"));
|
||||||
|
emit m_core->fetchItemsFromServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::postItems() {
|
||||||
|
showStatusMessage(tr("Invoked 'Server|Post items'"));
|
||||||
|
const QModelIndex currentIndex = ui->tableView->currentIndex();
|
||||||
|
const QByteArray jsonData = m_proxyModel->jsonDataForServer(currentIndex);
|
||||||
|
emit m_core->postItemToServer(jsonData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::deleteItem() {
|
||||||
|
showStatusMessage(tr("Invoked 'Server|Delete items'"));
|
||||||
|
const QModelIndex currentIndex = ui->tableView->currentIndex();
|
||||||
|
// const QByteArray jsonData = m_proxyModel->jsonDataForServer(currentIndex);
|
||||||
|
const QString currentId = m_proxyModel->getUuid(currentIndex);
|
||||||
|
emit m_core->deleteItemFromServer(currentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::execSettingsDialog() {
|
||||||
|
showStatusMessage(tr("Invoked 'Tools|Settings'"));
|
||||||
|
QVariantMap oldSettings = m_core->getSettings("Server");
|
||||||
|
// SettingsDialog* settingsDialog = new SettingsDialog(settingMap, this);
|
||||||
|
SettingsDialog* settingsDialog = new SettingsDialog(this);
|
||||||
|
settingsDialog->createContent();
|
||||||
|
settingsDialog->fillContent(oldSettings);
|
||||||
|
|
||||||
|
int returnCode = settingsDialog->exec();
|
||||||
|
if (returnCode == QDialog::Accepted) {
|
||||||
|
qDebug() << "Settings dialog accepted, writing settings...";
|
||||||
|
const QVariantMap settings = settingsDialog->getSettings();
|
||||||
|
|
||||||
|
m_core->applySettings(settings, "Server");
|
||||||
|
// TODO use signal-slot connection Core::syncServerSetupChanged(bool enabled) ->
|
||||||
|
// MainWindow::onSyncServerSetupChanged(bool enabled)
|
||||||
|
|
||||||
|
// enableDisableServerActions();
|
||||||
|
} else {
|
||||||
|
qDebug() << "Settings dialog rejected";
|
||||||
|
}
|
||||||
|
delete settingsDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::setupModelViews() {
|
||||||
|
// m_tableModel = m_core->getModel();
|
||||||
|
// ui->tableView->setModel(m_tableModel.get());
|
||||||
|
m_proxyModel = m_core->getSortFilterModel();
|
||||||
|
|
||||||
|
// TODO iterate over INT_ROLES and DOUBLE_ROLES to set spinbox delegate
|
||||||
|
/// setting number delegates to combo boxes
|
||||||
|
SpinboxDelegate* spinboxDelegate = new SpinboxDelegate(this);
|
||||||
|
const int amountColumn = GET_COLUMN_FOR_ROLE(AmountRole);
|
||||||
|
ui->tableView->setItemDelegateForColumn(amountColumn, spinboxDelegate);
|
||||||
|
const int factorColumn = GET_COLUMN_FOR_ROLE(FactorRole);
|
||||||
|
ui->tableView->setItemDelegateForColumn(factorColumn, spinboxDelegate);
|
||||||
|
|
||||||
|
// TODO iterate over TYPE_ROLES to set combobox delegate
|
||||||
|
/// setting type delegates to combo boxes
|
||||||
|
const int typeColumn = GET_COLUMN_FOR_ROLE(TypeRole);
|
||||||
|
ComboboxDelegate* shareTypeDelegate = new ComboboxDelegate(TYPES, this);
|
||||||
|
ui->tableView->setItemDelegateForColumn(typeColumn, shareTypeDelegate);
|
||||||
|
|
||||||
|
ui->tableView->setModel((QAbstractItemModel*)m_proxyModel.get());
|
||||||
|
ui->tableView->setSortingEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createActions() {
|
||||||
|
// TODO add generic menu actions (file/new, edit/cut, ...)
|
||||||
|
createFileActions();
|
||||||
|
createUndoActions();
|
||||||
|
createEditActions();
|
||||||
|
createServerActions();
|
||||||
|
createToolsActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createFileActions() {
|
||||||
|
m_newFileAct = make_unique<QAction>(tr("&New File"), this);
|
||||||
|
m_newFileAct->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_N));
|
||||||
|
m_newFileAct->setStatusTip(tr("Create a new file"));
|
||||||
|
// connect(m_newAct, &QAction::triggered, this, &MainWindow::newFile);
|
||||||
|
m_newFileAct->setEnabled(false);
|
||||||
|
ui->menu_File->addAction(m_newFileAct.get());
|
||||||
|
|
||||||
|
m_openAct = make_unique<QAction>(tr("&Open..."), this);
|
||||||
|
m_openAct->setShortcuts(QKeySequence::Open);
|
||||||
|
m_openAct->setStatusTip(tr("Open an existing file"));
|
||||||
|
// connect(m_openAct, &QAction::triggered, this, &MainWindow::open);
|
||||||
|
m_openAct->setEnabled(false);
|
||||||
|
ui->menu_File->addAction(m_openAct.get());
|
||||||
|
|
||||||
|
m_saveAct = make_unique<QAction>(tr("&Save"), this);
|
||||||
|
m_saveAct->setShortcuts(QKeySequence::Save);
|
||||||
|
m_saveAct->setStatusTip(tr("Save the document to disk"));
|
||||||
|
connect(m_saveAct.get(), &QAction::triggered, this, &MainWindow::saveItems);
|
||||||
|
ui->menu_File->addAction(m_saveAct.get());
|
||||||
|
|
||||||
|
ui->menu_File->addSeparator();
|
||||||
|
|
||||||
|
m_importAct = make_unique<QAction>(tr("&Import CSV..."), this);
|
||||||
|
m_importAct->setStatusTip(tr("Import an existing CSV file"));
|
||||||
|
connect(m_importAct.get(), &QAction::triggered, this, &MainWindow::importCSV);
|
||||||
|
ui->menu_File->addAction(m_importAct.get());
|
||||||
|
|
||||||
|
m_exportAct = make_unique<QAction>(tr("&Export CSV..."), this);
|
||||||
|
m_exportAct->setStatusTip(tr("Export content to a CSV document to disk"));
|
||||||
|
connect(m_exportAct.get(), &QAction::triggered, this, &MainWindow::exportCSV);
|
||||||
|
ui->menu_File->addAction(m_exportAct.get());
|
||||||
|
|
||||||
|
ui->menu_File->addSeparator();
|
||||||
|
|
||||||
|
m_printAct = make_unique<QAction>(tr("&Print..."), this);
|
||||||
|
m_printAct->setShortcuts(QKeySequence::Print);
|
||||||
|
m_printAct->setStatusTip(tr("Print the document"));
|
||||||
|
// connect(m_printAct, &QAction::triggered, this, &MainWindow::print);
|
||||||
|
m_printAct->setEnabled(false);
|
||||||
|
ui->menu_File->addAction(m_printAct.get());
|
||||||
|
|
||||||
|
ui->menu_File->addSeparator();
|
||||||
|
|
||||||
|
m_exitAct = make_unique<QAction>(tr("E&xit"), this);
|
||||||
|
m_exitAct->setShortcuts(QKeySequence::Quit);
|
||||||
|
m_exitAct->setStatusTip(tr("Exit the application"));
|
||||||
|
connect(m_exitAct.get(), &QAction::triggered, this, &QWidget::close);
|
||||||
|
ui->menu_File->addAction(m_exitAct.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createUndoActions() {
|
||||||
|
if (!m_core) {
|
||||||
|
qCritical() << "No core instance set, aborting...";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_modelUndoStack = m_core->getModelUndoStack();
|
||||||
|
|
||||||
|
connect(m_modelUndoStack, &QUndoStack::cleanChanged, this, &MainWindow::onCleanStateChanged);
|
||||||
|
|
||||||
|
m_undoAct.reset(m_modelUndoStack->createUndoAction(this, tr("&Undo")));
|
||||||
|
m_undoAct->setShortcuts(QKeySequence::Undo);
|
||||||
|
m_undoAct->setStatusTip(tr("Undo the last operation"));
|
||||||
|
ui->menu_Edit->addAction(m_undoAct.get());
|
||||||
|
|
||||||
|
m_redoAct.reset(m_modelUndoStack->createRedoAction(this, tr("&Redo")));
|
||||||
|
m_redoAct->setShortcuts(QKeySequence::Redo);
|
||||||
|
m_redoAct->setStatusTip(tr("Redo the last operation"));
|
||||||
|
ui->menu_Edit->addAction(m_redoAct.get());
|
||||||
|
|
||||||
|
m_modelUndoView = make_unique<QUndoView>(m_modelUndoStack);
|
||||||
|
m_modelUndoView->setWindowTitle(tr("Undo list"));
|
||||||
|
m_modelUndoView->setAttribute(Qt::WA_QuitOnClose, false);
|
||||||
|
m_modelUndoView->setMinimumSize(450, 600);
|
||||||
|
m_showModelUndoViewAct = make_unique<QAction>(tr("Show undo/redo window"), this);
|
||||||
|
m_showModelUndoViewAct->setStatusTip(tr("Opens a window displaying the items on the undo stack"));
|
||||||
|
|
||||||
|
// TODO showUndoViewAction should be checkable
|
||||||
|
// m_showUndoViewAction->setCheckable(true);
|
||||||
|
// connect(m_showUndoViewAction, &QAction::toggled, this, &MainWindow::onShowUndoViewToggled);
|
||||||
|
connect(m_showModelUndoViewAct.get(), &QAction::triggered, this,
|
||||||
|
&MainWindow::onShowUndoViewToggled);
|
||||||
|
ui->menu_View->addAction(m_showModelUndoViewAct.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createEditActions() {
|
||||||
|
m_cutAct = make_unique<QAction>(tr("Cu&t"), this);
|
||||||
|
m_cutAct->setShortcuts(QKeySequence::Cut);
|
||||||
|
m_cutAct->setStatusTip(
|
||||||
|
tr("Cut the current selection's contents to the "
|
||||||
|
"clipboard"));
|
||||||
|
// connect(m_cutAct, &QAction::triggered, this, &MainWindow::cut);
|
||||||
|
m_cutAct->setEnabled(false);
|
||||||
|
ui->menu_Edit->addAction(m_cutAct.get());
|
||||||
|
|
||||||
|
m_copyAct = make_unique<QAction>(tr("&Copy"), this);
|
||||||
|
m_copyAct->setShortcuts(QKeySequence::Copy);
|
||||||
|
m_copyAct->setStatusTip(
|
||||||
|
tr("Copy the current selection's contents to the "
|
||||||
|
"clipboard"));
|
||||||
|
// connect(m_copyAct, &QAction::triggered, this, &MainWindow::copy);
|
||||||
|
m_copyAct->setEnabled(false);
|
||||||
|
ui->menu_Edit->addAction(m_copyAct.get());
|
||||||
|
|
||||||
|
m_pasteAct = make_unique<QAction>(tr("&Paste"), this);
|
||||||
|
m_pasteAct->setShortcuts(QKeySequence::Paste);
|
||||||
|
m_pasteAct->setStatusTip(
|
||||||
|
tr("Paste the clipboard's contents into the current "
|
||||||
|
"selection"));
|
||||||
|
// connect(m_pasteAct, &QAction::triggered, this, &MainWindow::paste);
|
||||||
|
m_pasteAct->setEnabled(false);
|
||||||
|
ui->menu_Edit->addAction(m_pasteAct.get());
|
||||||
|
|
||||||
|
ui->menu_Edit->addSeparator();
|
||||||
|
|
||||||
|
m_openNewItemDialogAct = make_unique<QAction>(tr("&New item"), this);
|
||||||
|
m_openNewItemDialogAct->setShortcut(QKeySequence::New);
|
||||||
|
m_openNewItemDialogAct->setStatusTip(tr("Opens a dialog to add a new item"));
|
||||||
|
connect(m_openNewItemDialogAct.get(), &QAction::triggered, this, &MainWindow::openNewItemDialog);
|
||||||
|
ui->menu_Edit->addAction(m_openNewItemDialogAct.get());
|
||||||
|
|
||||||
|
m_openEditItemDialogAct = make_unique<QAction>(tr("&Edit item"), this);
|
||||||
|
m_openEditItemDialogAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_E));
|
||||||
|
m_openEditItemDialogAct->setStatusTip(tr("Opens a edit dialog for the current item"));
|
||||||
|
connect(m_openEditItemDialogAct.get(), &QAction::triggered, this,
|
||||||
|
&MainWindow::openEditItemDialog);
|
||||||
|
ui->menu_Edit->addAction(m_openEditItemDialogAct.get());
|
||||||
|
|
||||||
|
m_deleteItemAct = make_unique<QAction>(tr("&Delete item(s)"), this);
|
||||||
|
m_deleteItemAct->setShortcut(QKeySequence::Delete);
|
||||||
|
m_deleteItemAct->setStatusTip(tr("Delete currently selected item(s)"));
|
||||||
|
// connect(m_deleteItemAct.get(), &QAction::triggered, this, &MainWindow::deleteSelectedtItems);
|
||||||
|
connect(m_deleteItemAct.get(), &QAction::triggered, this, &MainWindow::deleteCurrentItem);
|
||||||
|
ui->menu_Edit->addAction(m_deleteItemAct.get());
|
||||||
|
|
||||||
|
ui->menu_Edit->addSeparator();
|
||||||
|
|
||||||
|
m_findItemAct = make_unique<QAction>(tr("&Find item(s)"), this);
|
||||||
|
m_findItemAct->setShortcuts(QKeySequence::Find);
|
||||||
|
m_findItemAct->setStatusTip(tr("Opens a dialog to find item(s) by containing text"));
|
||||||
|
connect(m_findItemAct.get(), &QAction::triggered, this, &MainWindow::findItems);
|
||||||
|
ui->menu_Edit->addAction(m_findItemAct.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createServerActions() {
|
||||||
|
m_fetchItemsAct = make_unique<QAction>(tr("&Fetch item(s)"), this);
|
||||||
|
m_fetchItemsAct->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Down));
|
||||||
|
m_fetchItemsAct->setStatusTip(tr("Fetches all item on configured server"));
|
||||||
|
connect(m_fetchItemsAct.get(), &QAction::triggered, this, &MainWindow::fetchItems);
|
||||||
|
ui->menu_Server->addAction(m_fetchItemsAct.get());
|
||||||
|
|
||||||
|
m_postItemsAct = make_unique<QAction>(tr("&Post item(s)"), this);
|
||||||
|
m_postItemsAct->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Up));
|
||||||
|
// m_postItemsAct->setStatusTip(tr("Posts the selected items on configured server"));
|
||||||
|
m_postItemsAct->setStatusTip(tr("Posts the current item on configured server"));
|
||||||
|
connect(m_postItemsAct.get(), &QAction::triggered, this, &MainWindow::postItems);
|
||||||
|
ui->menu_Server->addAction(m_postItemsAct.get());
|
||||||
|
|
||||||
|
m_deleteItemsAct = make_unique<QAction>(tr("&Delete item"), this);
|
||||||
|
m_deleteItemsAct->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Backspace));
|
||||||
|
// m_deleteItemsAct->setStatusTip(tr("Deletes the selected items on configured server"));
|
||||||
|
m_deleteItemsAct->setStatusTip(tr("Deletes the current item on configured server"));
|
||||||
|
connect(m_deleteItemsAct.get(), &QAction::triggered, this, &MainWindow::deleteItem);
|
||||||
|
ui->menu_Server->addAction(m_deleteItemsAct.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createToolsActions() {
|
||||||
|
QMenu* menu = ui->menu_Tools;
|
||||||
|
QAction* settingsAct = menu->addAction(tr("&Settings"), this, &MainWindow::execSettingsDialog);
|
||||||
|
settingsAct->setStatusTip(tr("Opens a dialog to configure applications settings."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createHelpMenu() {
|
||||||
|
QMenu* helpMenu = ui->menu_Help;
|
||||||
|
helpMenu->addSeparator();
|
||||||
|
QAction* aboutAct = helpMenu->addAction(tr("&About"), this, &MainWindow::onAboutClicked);
|
||||||
|
aboutAct->setStatusTip(tr("Show the application's About box"));
|
||||||
|
|
||||||
|
QAction* aboutQtAct = helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
|
||||||
|
aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::createGuiDialogs() {
|
||||||
|
/// new item dialog
|
||||||
|
m_newItemDialog = make_unique<NewItemDialog>(this);
|
||||||
|
m_newItemDialog->createContent();
|
||||||
|
connect(m_newItemDialog.get(), &NewItemDialog::addItems, m_proxyModel.get(),
|
||||||
|
&GeneralSortFilterModel::appendItems);
|
||||||
|
/// edit item dialog
|
||||||
|
m_editItemDialog = make_unique<EditItemDialog>(ui->tableView, this);
|
||||||
|
m_editItemDialog->createContent();
|
||||||
|
}
|
||||||
|
|||||||
97
mainwindow.h
97
mainwindow.h
@ -1,17 +1,27 @@
|
|||||||
#ifndef MAINWINDOW_H
|
#ifndef MAINWINDOW_H
|
||||||
#define MAINWINDOW_H
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QItemSelection>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class GenericCore;
|
class QUndoStack;
|
||||||
|
|
||||||
|
class QUndoView;
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
}
|
}
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class GenericCore;
|
||||||
|
class TableModel;
|
||||||
|
class GeneralSortFilterModel;
|
||||||
|
class NewItemDialog;
|
||||||
|
class EditItemDialog;
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
class MainWindow : public QMainWindow {
|
class MainWindow : public QMainWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -19,12 +29,95 @@ class MainWindow : public QMainWindow {
|
|||||||
MainWindow(QWidget* parent = nullptr);
|
MainWindow(QWidget* parent = nullptr);
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void displayStatusMessage(QString message);
|
||||||
|
void checkForUpdates();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent* event) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void showStatusMessage(const QString text);
|
||||||
|
void onCurrentChanged(const QModelIndex& current, const QModelIndex& previous);
|
||||||
|
void onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
||||||
|
|
||||||
|
void onAboutClicked();
|
||||||
|
void on_actionCheck_for_update_triggered();
|
||||||
|
|
||||||
void on_pushButton_clicked();
|
void on_pushButton_clicked();
|
||||||
|
|
||||||
|
/// slots for menu actions
|
||||||
|
void openNewItemDialog();
|
||||||
|
void openEditItemDialog();
|
||||||
|
void deleteCurrentItem();
|
||||||
|
void deleteSelectedtItems();
|
||||||
|
|
||||||
|
void onCleanStateChanged(bool clean);
|
||||||
|
void onShowUndoViewToggled(bool checked);
|
||||||
|
|
||||||
|
/// 'File' slots
|
||||||
|
void saveItems();
|
||||||
|
void importCSV();
|
||||||
|
void exportCSV();
|
||||||
|
|
||||||
|
/// 'Edit' slots
|
||||||
|
void findItems();
|
||||||
|
|
||||||
|
/// 'Server' slots
|
||||||
|
void fetchItems();
|
||||||
|
void postItems();
|
||||||
|
void deleteItem();
|
||||||
|
|
||||||
|
/// 'Tools' slots
|
||||||
|
void execSettingsDialog();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow* ui;
|
Ui::MainWindow* ui;
|
||||||
|
|
||||||
std::shared_ptr<GenericCore> m_core;
|
unique_ptr<GenericCore> m_core;
|
||||||
|
shared_ptr<GeneralSortFilterModel> m_proxyModel;
|
||||||
|
QUndoStack* m_modelUndoStack;
|
||||||
|
unique_ptr<QUndoView> m_modelUndoView;
|
||||||
|
|
||||||
|
/// File actions
|
||||||
|
unique_ptr<QAction> m_newFileAct;
|
||||||
|
unique_ptr<QAction> m_openAct;
|
||||||
|
unique_ptr<QAction> m_saveAct;
|
||||||
|
unique_ptr<QAction> m_importAct;
|
||||||
|
unique_ptr<QAction> m_exportAct;
|
||||||
|
unique_ptr<QAction> m_printAct;
|
||||||
|
unique_ptr<QAction> m_exitAct;
|
||||||
|
/// Edit actions
|
||||||
|
unique_ptr<QAction> m_undoAct;
|
||||||
|
unique_ptr<QAction> m_redoAct;
|
||||||
|
unique_ptr<QAction> m_cutAct;
|
||||||
|
unique_ptr<QAction> m_copyAct;
|
||||||
|
unique_ptr<QAction> m_pasteAct;
|
||||||
|
unique_ptr<QAction> m_openNewItemDialogAct;
|
||||||
|
unique_ptr<QAction> m_openEditItemDialogAct;
|
||||||
|
unique_ptr<QAction> m_deleteItemAct;
|
||||||
|
unique_ptr<QAction> m_findItemAct;
|
||||||
|
/// Server actions
|
||||||
|
unique_ptr<QAction> m_fetchItemsAct;
|
||||||
|
unique_ptr<QAction> m_postItemsAct;
|
||||||
|
unique_ptr<QAction> m_deleteItemsAct;
|
||||||
|
|
||||||
|
/// View actions
|
||||||
|
unique_ptr<QAction> m_showModelUndoViewAct;
|
||||||
|
|
||||||
|
/// Dialogs
|
||||||
|
unique_ptr<NewItemDialog> m_newItemDialog;
|
||||||
|
unique_ptr<EditItemDialog> m_editItemDialog;
|
||||||
|
|
||||||
|
/// Setup functions
|
||||||
|
void setupModelViews();
|
||||||
|
void createActions();
|
||||||
|
void createFileActions();
|
||||||
|
void createUndoActions();
|
||||||
|
void createEditActions();
|
||||||
|
void createServerActions();
|
||||||
|
void createToolsActions();
|
||||||
|
void createHelpMenu();
|
||||||
|
void createGuiDialogs();
|
||||||
};
|
};
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
|||||||
@ -15,6 +15,9 @@
|
|||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralwidget">
|
<widget class="QWidget" name="centralwidget">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="tableView"/>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -37,11 +40,53 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>800</width>
|
<width>800</width>
|
||||||
<height>25</height>
|
<height>22</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<widget class="QMenu" name="menu_File">
|
||||||
|
<property name="title">
|
||||||
|
<string>&File</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Edit">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Edit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_View">
|
||||||
|
<property name="title">
|
||||||
|
<string>&View</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Help">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Help</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionCheck_for_update"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Server">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Server</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_Tools">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Tools</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menu_File"/>
|
||||||
|
<addaction name="menu_Edit"/>
|
||||||
|
<addaction name="menu_View"/>
|
||||||
|
<addaction name="menu_Server"/>
|
||||||
|
<addaction name="menu_Tools"/>
|
||||||
|
<addaction name="menu_Help"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusbar"/>
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
<action name="actionCheck_for_update">
|
||||||
|
<property name="text">
|
||||||
|
<string>Check for &update</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|||||||
@ -1,164 +0,0 @@
|
|||||||
#ifndef MESSAGEHANDLER_H
|
|
||||||
#define MESSAGEHANDLER_H
|
|
||||||
/**
|
|
||||||
* Color and formatting codes
|
|
||||||
* @see: http://misc.flogisoft.com/bash/tip_colors_and_formatting
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
// qSetMessagePattern("%{file}(%{line}): %{message}");
|
|
||||||
// qSetMessagePattern("%{type}(%{line}):\t%{message}");
|
|
||||||
// qSetMessagePattern("%{type}%{file}(%{line}):\t%{message}");
|
|
||||||
|
|
||||||
void consoleHandlerColoredVerbose(QtMsgType type,
|
|
||||||
const QMessageLogContext& context,
|
|
||||||
const QString& msg) {
|
|
||||||
QByteArray localMsg = msg.toLocal8Bit();
|
|
||||||
switch (type) {
|
|
||||||
case QtDebugMsg:
|
|
||||||
// fprintf(stderr, "\033[1;30mDebug: (%s:%u, %s) \t%s\n\033[0m", context.file,
|
|
||||||
// context.line, context.function, localMsg.constData()); // bold
|
|
||||||
fprintf(stderr, "\033[107;30mDebug: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
context.function, localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtInfoMsg:
|
|
||||||
fprintf(stderr, "\033[107;32mInfo: (%s:%u) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtWarningMsg:
|
|
||||||
fprintf(stderr, "\033[43;30mWarning: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
context.function, localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtCriticalMsg:
|
|
||||||
fprintf(stderr, "\033[41;30mCritical: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
context.function, localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtFatalMsg:
|
|
||||||
fprintf(stderr, "\033[41;30mFatal: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
context.function, localMsg.constData());
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void consoleHandlerColoredVerboseInDarkTheme(QtMsgType type,
|
|
||||||
const QMessageLogContext& context,
|
|
||||||
const QString& msg) {
|
|
||||||
QByteArray localMsg = msg.toLocal8Bit();
|
|
||||||
switch (type) {
|
|
||||||
case QtDebugMsg:
|
|
||||||
// fprintf(stderr, "\033[1;30mDebug: (%s:%u, %s) \t%s\n\033[0m", context.file,
|
|
||||||
// context.line, context.function, localMsg.constData()); // bold
|
|
||||||
fprintf(stderr, "\033[107;37mDebug: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
context.function, localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtInfoMsg:
|
|
||||||
fprintf(stderr, "\033[107;32mInfo: (%s:%u) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtWarningMsg:
|
|
||||||
fprintf(stderr, "\033[43;30mWarning: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
context.function, localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtCriticalMsg:
|
|
||||||
fprintf(stderr, "\033[41;30mCritical: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
context.function, localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtFatalMsg:
|
|
||||||
fprintf(stderr, "\033[41;30mFatal: (%s:%u, %s) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
context.function, localMsg.constData());
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void consoleHandlerColored(QtMsgType type, const QMessageLogContext& context, const QString& msg) {
|
|
||||||
QByteArray localMsg = msg.toLocal8Bit();
|
|
||||||
switch (type) {
|
|
||||||
case QtDebugMsg:
|
|
||||||
fprintf(stderr, "\033[1;30mDebug: (%s:%u) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtInfoMsg:
|
|
||||||
fprintf(stderr, "\033[0;30mInfo: (%s:%u) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtWarningMsg:
|
|
||||||
fprintf(stderr, "\033[1;33mWarning: (%s:%u) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtCriticalMsg:
|
|
||||||
fprintf(stderr, "\033[31mCritical: (%s:%u) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
localMsg.constData());
|
|
||||||
break;
|
|
||||||
case QtFatalMsg:
|
|
||||||
fprintf(stderr, "\033[31mFatal: (%s:%u) \t%s\n\033[0m", context.file, context.line,
|
|
||||||
localMsg.constData());
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void myMessageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg) {
|
|
||||||
QByteArray localMsg = msg.toLocal8Bit();
|
|
||||||
switch (type) {
|
|
||||||
case QtDebugMsg:
|
|
||||||
fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line,
|
|
||||||
context.function);
|
|
||||||
break;
|
|
||||||
case QtInfoMsg:
|
|
||||||
fprintf(stderr, "Info: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line,
|
|
||||||
context.function);
|
|
||||||
break;
|
|
||||||
case QtWarningMsg:
|
|
||||||
fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line,
|
|
||||||
context.function);
|
|
||||||
break;
|
|
||||||
case QtCriticalMsg:
|
|
||||||
fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file,
|
|
||||||
context.line, context.function);
|
|
||||||
break;
|
|
||||||
case QtFatalMsg:
|
|
||||||
fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line,
|
|
||||||
context.function);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
#include <android/log.h>
|
|
||||||
|
|
||||||
const char* const applicationName = "Pensieve";
|
|
||||||
void androidMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) {
|
|
||||||
QString report = msg;
|
|
||||||
if (context.file && !QString(context.file).isEmpty()) {
|
|
||||||
report += " in file ";
|
|
||||||
report += QString(context.file);
|
|
||||||
report += " line ";
|
|
||||||
report += QString::number(context.line);
|
|
||||||
}
|
|
||||||
if (context.function && !QString(context.function).isEmpty()) {
|
|
||||||
report += +" function ";
|
|
||||||
report += QString(context.function);
|
|
||||||
}
|
|
||||||
const char* const local = report.toLocal8Bit().constData();
|
|
||||||
switch (type) {
|
|
||||||
case QtDebugMsg:
|
|
||||||
__android_log_write(ANDROID_LOG_DEBUG, applicationName, local);
|
|
||||||
break;
|
|
||||||
case QtInfoMsg:
|
|
||||||
__android_log_write(ANDROID_LOG_INFO, applicationName, local);
|
|
||||||
break;
|
|
||||||
case QtWarningMsg:
|
|
||||||
__android_log_write(ANDROID_LOG_WARN, applicationName, local);
|
|
||||||
break;
|
|
||||||
case QtCriticalMsg:
|
|
||||||
__android_log_write(ANDROID_LOG_ERROR, applicationName, local);
|
|
||||||
break;
|
|
||||||
case QtFatalMsg:
|
|
||||||
default:
|
|
||||||
__android_log_write(ANDROID_LOG_FATAL, applicationName, local);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // MESSAGEHANDLER_H
|
|
||||||
191
views/itemdetailmapper.cpp
Normal file
191
views/itemdetailmapper.cpp
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
#include "itemdetailmapper.h"
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QDataWidgetMapper>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QTableView>
|
||||||
|
|
||||||
|
#include "../widgethelper.h"
|
||||||
|
|
||||||
|
ItemDetailMapper::ItemDetailMapper(QTableView* tableView, QWidget* parent)
|
||||||
|
: QWidget{parent} {
|
||||||
|
/// model mapping
|
||||||
|
m_mapper = std::make_unique<QDataWidgetMapper>(this);
|
||||||
|
/// BUG: If multiple columns are changed not all changes are applied.
|
||||||
|
/// Multiple changes are set individually by calling setData().
|
||||||
|
/// Probably due to a conflicting dataChanged signal for too many roles&columns the data of
|
||||||
|
/// the remaining columns is reset before setData is called.
|
||||||
|
/// And a manual submit would also create multiple undo steps anyway.
|
||||||
|
/// Workaround: ManualSubmit -> AutoSubmit
|
||||||
|
// m_mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
|
||||||
|
m_mapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
|
||||||
|
|
||||||
|
qDebug() << "Setting model...";
|
||||||
|
m_tableView = tableView;
|
||||||
|
m_model = tableView->model();
|
||||||
|
m_selectionModel = tableView->selectionModel();
|
||||||
|
|
||||||
|
m_mapper->setModel(m_model);
|
||||||
|
|
||||||
|
setupWidgets();
|
||||||
|
|
||||||
|
setupConnections();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ItemDetailMapper::submit() { return m_mapper->submit(); }
|
||||||
|
|
||||||
|
void ItemDetailMapper::revert() { m_mapper->revert(); }
|
||||||
|
|
||||||
|
void ItemDetailMapper::onCurrentIndexChanged(const QModelIndex& current,
|
||||||
|
const QModelIndex& /*previous*/) {
|
||||||
|
if (!isEnabled()) {
|
||||||
|
setEnabled(true);
|
||||||
|
}
|
||||||
|
m_mapper->setCurrentModelIndex(current);
|
||||||
|
updateButtons(current.row());
|
||||||
|
emitContentChanged(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::rowsInserted(const QModelIndex& parent, int start, int end) {
|
||||||
|
updateButtons(m_mapper->currentIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::rowsRemoved(const QModelIndex& parent, int start, int end) {
|
||||||
|
if (m_model->rowCount() == 0) {
|
||||||
|
clearControlWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateButtons(m_mapper->currentIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::toPrevious() {
|
||||||
|
int currentRow = m_selectionModel->currentIndex().row();
|
||||||
|
QModelIndex previousIndex = m_selectionModel->currentIndex().siblingAtRow(currentRow - 1);
|
||||||
|
if (previousIndex.isValid()) {
|
||||||
|
m_selectionModel->setCurrentIndex(previousIndex, QItemSelectionModel::ClearAndSelect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::toNext() {
|
||||||
|
int currentRow = m_selectionModel->currentIndex().row();
|
||||||
|
QModelIndex nextIndex = m_selectionModel->currentIndex().siblingAtRow(currentRow + 1);
|
||||||
|
if (nextIndex.isValid()) {
|
||||||
|
m_selectionModel->setCurrentIndex(nextIndex, QItemSelectionModel::ClearAndSelect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::updateButtons(int row) {
|
||||||
|
m_previousButton->setEnabled(row > 0);
|
||||||
|
m_nextButton->setEnabled(row < m_model->rowCount() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::emitContentChanged(const QModelIndex& currentIndex) {
|
||||||
|
// BUG QR-Code isn't updated after changes through the ItemDetailMapper #18
|
||||||
|
QString toStringText = "";
|
||||||
|
if (currentIndex.isValid()) {
|
||||||
|
toStringText = currentIndex.data(ToStringRole).toString();
|
||||||
|
}
|
||||||
|
emit contentChanged(toStringText);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::setupConnections() {
|
||||||
|
m_mapper->setCurrentIndex(m_selectionModel->currentIndex().row());
|
||||||
|
|
||||||
|
connect(m_model, &QAbstractItemModel::rowsInserted, this, &ItemDetailMapper::rowsInserted);
|
||||||
|
connect(m_model, &QAbstractItemModel::rowsRemoved, this, &ItemDetailMapper::rowsRemoved);
|
||||||
|
connect(m_selectionModel, &QItemSelectionModel::currentChanged, this,
|
||||||
|
&ItemDetailMapper::onCurrentIndexChanged);
|
||||||
|
|
||||||
|
updateButtons(m_selectionModel->currentIndex().row());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::setupNavigationButtons() {
|
||||||
|
m_nextButton = new QPushButton(tr("Ne&xt"));
|
||||||
|
m_previousButton = new QPushButton(tr("&Previous"));
|
||||||
|
|
||||||
|
connect(m_previousButton, &QAbstractButton::clicked, this, &ItemDetailMapper::toPrevious);
|
||||||
|
connect(m_nextButton, &QAbstractButton::clicked, this, &ItemDetailMapper::toNext);
|
||||||
|
|
||||||
|
const int nRows = m_layout->rowCount();
|
||||||
|
m_layout->addWidget(m_previousButton, nRows, 0);
|
||||||
|
m_layout->addWidget(m_nextButton, nRows, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::setupWidgets() {
|
||||||
|
m_layout = new QGridLayout();
|
||||||
|
|
||||||
|
for (int i = 0; i < USER_FACING_ROLES.size(); ++i) {
|
||||||
|
setupWidgetPairForColumn(i);
|
||||||
|
}
|
||||||
|
setupNavigationButtons();
|
||||||
|
|
||||||
|
setLayout(m_layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::setupWidgetPairForColumn(const int column) {
|
||||||
|
// REFACTOR consolidate ItemDetailMapper::setupWidgetPairForColumn(...)
|
||||||
|
// with NewItemDialog::setupWidgetPairForColumn(...)
|
||||||
|
const UserRoles role = GET_ROLE_FOR_COLUMN(column);
|
||||||
|
|
||||||
|
QWidget* control = WidgetHelper::createControlWidget(role, this);
|
||||||
|
|
||||||
|
const QString string = QString("&%1").arg(GET_HEADER_FOR_COLUMN(column));
|
||||||
|
QLabel* label = new QLabel(string);
|
||||||
|
label->setBuddy(control);
|
||||||
|
|
||||||
|
m_layout->addWidget(label, column, 0);
|
||||||
|
m_layout->addWidget(control, column, 1);
|
||||||
|
m_controlWidgets.append(control);
|
||||||
|
|
||||||
|
if (TYPE_ROLES.contains(role)) {
|
||||||
|
m_mapper->addMapping(control, column, "currentText");
|
||||||
|
} else {
|
||||||
|
m_mapper->addMapping(control, column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::clearControlWidgets() {
|
||||||
|
setEnabled(false);
|
||||||
|
|
||||||
|
for (int i = 0; i < m_controlWidgets.size(); ++i) {
|
||||||
|
const UserRoles role = GET_ROLE_FOR_COLUMN(i);
|
||||||
|
if (STRING_ROLES.contains(role)) {
|
||||||
|
clearLineEdit(i);
|
||||||
|
} else if (TYPE_ROLES.contains(role)) {
|
||||||
|
clearComboBox(i);
|
||||||
|
} else if (INT_ROLES.contains(role)) {
|
||||||
|
clearSpinBox(i);
|
||||||
|
} else if (DOUBLE_ROLES.contains(role)) {
|
||||||
|
clearSpinBox(i);
|
||||||
|
} else {
|
||||||
|
qCritical() << "Could not reset content for control widget in column:" << i << "!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::clearLineEdit(const int column) {
|
||||||
|
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(m_controlWidgets[column]);
|
||||||
|
if (lineEdit) {
|
||||||
|
lineEdit->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::clearComboBox(const int column) {
|
||||||
|
QComboBox* comboBox = dynamic_cast<QComboBox*>(m_controlWidgets[column]);
|
||||||
|
if (comboBox) {
|
||||||
|
comboBox->setCurrentText("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemDetailMapper::clearSpinBox(const int column) {
|
||||||
|
QAbstractSpinBox* spinBox = dynamic_cast<QAbstractSpinBox*>(m_controlWidgets[column]);
|
||||||
|
if (spinBox) {
|
||||||
|
spinBox->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
68
views/itemdetailmapper.h
Normal file
68
views/itemdetailmapper.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#ifndef ITEMDETAILMAPPER_H
|
||||||
|
#define ITEMDETAILMAPPER_H
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QDataWidgetMapper>
|
||||||
|
#include <QStringListModel>
|
||||||
|
#include <QWidget>
|
||||||
|
#include "model/metadata.h"
|
||||||
|
|
||||||
|
class QGridLayout;
|
||||||
|
class QLabel;
|
||||||
|
class QLineEdit;
|
||||||
|
class QDoubleSpinBox;
|
||||||
|
class QSpinBox;
|
||||||
|
class QPushButton;
|
||||||
|
class QAbstractItemModel;
|
||||||
|
class QItemSelectionModel;
|
||||||
|
class QTableView;
|
||||||
|
|
||||||
|
class ItemDetailMapper : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ItemDetailMapper(QTableView* tableView, QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
bool submit();
|
||||||
|
void revert();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void contentChanged(const QString text);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onCurrentIndexChanged(const QModelIndex& current, const QModelIndex& previous);
|
||||||
|
void rowsInserted(const QModelIndex& parent, int start, int end);
|
||||||
|
void rowsRemoved(const QModelIndex& parent, int start, int end);
|
||||||
|
void toPrevious();
|
||||||
|
void toNext();
|
||||||
|
void updateButtons(int row);
|
||||||
|
void emitContentChanged(const QModelIndex& currentIndex);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// *** members ***
|
||||||
|
/// Model stuff
|
||||||
|
QTableView* m_tableView = nullptr;
|
||||||
|
QAbstractItemModel* m_model = nullptr;
|
||||||
|
QItemSelectionModel* m_selectionModel = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<QDataWidgetMapper> m_mapper;
|
||||||
|
|
||||||
|
/// GUI elements
|
||||||
|
QGridLayout* m_layout;
|
||||||
|
QList<QWidget*> m_controlWidgets;
|
||||||
|
|
||||||
|
QPushButton* m_nextButton;
|
||||||
|
QPushButton* m_previousButton;
|
||||||
|
|
||||||
|
void setupConnections();
|
||||||
|
void setupNavigationButtons();
|
||||||
|
void setupWidgets();
|
||||||
|
|
||||||
|
void setupWidgetPairForColumn(const int column);
|
||||||
|
|
||||||
|
void clearControlWidgets();
|
||||||
|
void clearLineEdit(const int column);
|
||||||
|
void clearComboBox(const int column);
|
||||||
|
void clearSpinBox(const int column);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ITEMDETAILMAPPER_H
|
||||||
66
widgethelper.cpp
Normal file
66
widgethelper.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include "widgethelper.h"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QStringListModel>
|
||||||
|
|
||||||
|
QWidget* WidgetHelper::createControlWidget(const UserRoles role, QWidget* parent) {
|
||||||
|
QWidget* control;
|
||||||
|
if (STRING_ROLES.contains(role)) {
|
||||||
|
control = createLineEdit(role, parent);
|
||||||
|
} else if (TYPE_ROLES.contains(role)) {
|
||||||
|
control = createComboBox(role, parent);
|
||||||
|
} else if (NUMBER_ROLES.contains(role)) {
|
||||||
|
control = createSpinBox(role, parent);
|
||||||
|
} else {
|
||||||
|
qCritical() << QString("Unsupported role %1!!!").arg(role);
|
||||||
|
qDebug() << "Using line edit as well and pretend it's a string role...";
|
||||||
|
control = createLineEdit(role, parent);
|
||||||
|
}
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetHelper::WidgetHelper() {}
|
||||||
|
|
||||||
|
QWidget* WidgetHelper::createLineEdit(const UserRoles role, QWidget* /*parent*/) {
|
||||||
|
QLineEdit* lineEdit = new QLineEdit();
|
||||||
|
if (READ_ONLY_ROLES.contains(role)) {
|
||||||
|
lineEdit->setReadOnly(true);
|
||||||
|
}
|
||||||
|
return lineEdit;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* WidgetHelper::createSpinBox(const UserRoles role, QWidget* /*parent*/) {
|
||||||
|
QAbstractSpinBox* abstractSpinBox;
|
||||||
|
if (DOUBLE_ROLES.contains(role)) {
|
||||||
|
QDoubleSpinBox* spinBox = new QDoubleSpinBox();
|
||||||
|
spinBox->setMaximum(1000);
|
||||||
|
abstractSpinBox = spinBox;
|
||||||
|
} else {
|
||||||
|
QSpinBox* spinBox = new QSpinBox();
|
||||||
|
spinBox->setMaximum(1000);
|
||||||
|
abstractSpinBox = spinBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (READ_ONLY_ROLES.contains(role)) {
|
||||||
|
abstractSpinBox->setReadOnly(true);
|
||||||
|
}
|
||||||
|
return abstractSpinBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* WidgetHelper::createComboBox(const UserRoles role, QWidget* parent) {
|
||||||
|
// TODO add support for read only type roles?
|
||||||
|
QStringListModel* typeModel;
|
||||||
|
if (role == TypeRole) {
|
||||||
|
typeModel = new QStringListModel(TYPES, parent);
|
||||||
|
} else {
|
||||||
|
qCritical() << "Unsupported type with role:" << role
|
||||||
|
<< "- Using string list model with only one empty string!";
|
||||||
|
typeModel = new QStringListModel({""}, parent);
|
||||||
|
}
|
||||||
|
QComboBox* comboBox = new QComboBox();
|
||||||
|
comboBox->setModel(typeModel);
|
||||||
|
comboBox->setCurrentText("");
|
||||||
|
return comboBox;
|
||||||
|
}
|
||||||
20
widgethelper.h
Normal file
20
widgethelper.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef WIDGETHELPER_H
|
||||||
|
#define WIDGETHELPER_H
|
||||||
|
|
||||||
|
#include "model/metadata.h"
|
||||||
|
|
||||||
|
class QWidget;
|
||||||
|
|
||||||
|
class WidgetHelper {
|
||||||
|
public:
|
||||||
|
static QWidget* createControlWidget(const UserRoles role, QWidget* parent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit WidgetHelper();
|
||||||
|
|
||||||
|
static QWidget* createLineEdit(const UserRoles role, QWidget* parent);
|
||||||
|
static QWidget* createSpinBox(const UserRoles role, QWidget* parent);
|
||||||
|
static QWidget* createComboBox(const UserRoles role, QWidget* parent);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // WIDGETHELPER_H
|
||||||
57
widgets/controls/comboboxdelegate.cpp
Normal file
57
widgets/controls/comboboxdelegate.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include "comboboxdelegate.h"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QStringListModel>
|
||||||
|
#include "model/metadata.h"
|
||||||
|
|
||||||
|
ComboboxDelegate::ComboboxDelegate(const QStringList items, QObject* parent)
|
||||||
|
: QStyledItemDelegate(parent)
|
||||||
|
, m_types(new QStringListModel(items)) {}
|
||||||
|
|
||||||
|
void ComboboxDelegate::paint(QPainter* painter,
|
||||||
|
const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex& index) const {
|
||||||
|
QStyledItemDelegate::paint(painter, option, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize ComboboxDelegate::sizeHint(const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex& index) const {
|
||||||
|
return QStyledItemDelegate::sizeHint(option, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* ComboboxDelegate::createEditor(QWidget* parent,
|
||||||
|
const QStyleOptionViewItem& /*option*/,
|
||||||
|
const QModelIndex& /*index*/) const {
|
||||||
|
QComboBox* editor = new QComboBox(parent);
|
||||||
|
editor->setModel(m_types);
|
||||||
|
return editor;
|
||||||
|
// return QStyledItemDelegate::createEditor(parent, option, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComboboxDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const {
|
||||||
|
/// Get the value via index of the Model
|
||||||
|
const QAbstractItemModel* localModel = index.model();
|
||||||
|
const QString headerText = localModel->headerData(index.column(), Qt::Horizontal).toString();
|
||||||
|
|
||||||
|
const UserRoles role = GET_ROLE_FOR_COLUMN(index.column());
|
||||||
|
const bool isType = TYPE_ROLES.contains(role);
|
||||||
|
/// Put the value into the SpinBox
|
||||||
|
if (isType) {
|
||||||
|
const QString valueString = index.model()->data(index, TypeRole).toString();
|
||||||
|
int value = TYPES.indexOf(valueString);
|
||||||
|
|
||||||
|
QComboBox* combobox = static_cast<QComboBox*>(editor);
|
||||||
|
combobox->setCurrentIndex(value);
|
||||||
|
// QStyledItemDelegate::setEditorData(editor, index);
|
||||||
|
} else {
|
||||||
|
qCritical() << "Could not find the correct type role for index:" << index << "!!!";
|
||||||
|
QComboBox* combobox = static_cast<QComboBox*>(editor);
|
||||||
|
combobox->setCurrentIndex(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComboboxDelegate::setModelData(QWidget* editor,
|
||||||
|
QAbstractItemModel* model,
|
||||||
|
const QModelIndex& index) const {
|
||||||
|
QStyledItemDelegate::setModelData(editor, model, index);
|
||||||
|
}
|
||||||
31
widgets/controls/comboboxdelegate.h
Normal file
31
widgets/controls/comboboxdelegate.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef COMBOBOXDELEGATE_H
|
||||||
|
#define COMBOBOXDELEGATE_H
|
||||||
|
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
class QStringListModel;
|
||||||
|
|
||||||
|
class ComboboxDelegate : public QStyledItemDelegate {
|
||||||
|
// TODO move source code files into subfolder "widgets/delegate"
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ComboboxDelegate(const QStringList items, QObject* parent = nullptr);
|
||||||
|
|
||||||
|
/// QAbstractItemDelegate interface
|
||||||
|
public:
|
||||||
|
void paint(QPainter* painter,
|
||||||
|
const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex& index) const override;
|
||||||
|
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||||
|
QWidget* createEditor(QWidget* parent,
|
||||||
|
const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex&) const override;
|
||||||
|
void setEditorData(QWidget* editor, const QModelIndex& index) const override;
|
||||||
|
void setModelData(QWidget* editor,
|
||||||
|
QAbstractItemModel* model,
|
||||||
|
const QModelIndex& index) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStringListModel* m_types = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COMBOBOXDELEGATE_H
|
||||||
69
widgets/controls/spinboxdelegate.cpp
Normal file
69
widgets/controls/spinboxdelegate.cpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#include "spinboxdelegate.h"
|
||||||
|
|
||||||
|
#include <QSpinBox>
|
||||||
|
|
||||||
|
#include "model/metadata.h"
|
||||||
|
|
||||||
|
SpinboxDelegate::SpinboxDelegate(QObject* parent)
|
||||||
|
: QStyledItemDelegate(parent) {}
|
||||||
|
|
||||||
|
void SpinboxDelegate::paint(QPainter* painter,
|
||||||
|
const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex& index) const {
|
||||||
|
QStyledItemDelegate::paint(painter, option, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize SpinboxDelegate::sizeHint(const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex& index) const {
|
||||||
|
return QStyledItemDelegate::sizeHint(option, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* SpinboxDelegate::createEditor(QWidget* parent,
|
||||||
|
const QStyleOptionViewItem& /*option*/,
|
||||||
|
const QModelIndex& index) const {
|
||||||
|
const QAbstractItemModel* localModel = index.model();
|
||||||
|
QString headerText = localModel->headerData(index.column(), Qt::Horizontal).toString();
|
||||||
|
|
||||||
|
const UserRoles role = GET_ROLE_FOR_COLUMN(index.column());
|
||||||
|
const bool isInt = INT_ROLES.contains(role);
|
||||||
|
if (isInt) {
|
||||||
|
QSpinBox* editor = new QSpinBox(parent);
|
||||||
|
editor->setMinimum(0);
|
||||||
|
editor->setMaximum(23000);
|
||||||
|
return editor;
|
||||||
|
} else {
|
||||||
|
QDoubleSpinBox* editor = new QDoubleSpinBox(parent);
|
||||||
|
editor->setMinimum(0);
|
||||||
|
editor->setMaximum(23000);
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
// return QStyledItemDelegate::createEditor(parent, option, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpinboxDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const {
|
||||||
|
// Get the value via index of the Model
|
||||||
|
const QAbstractItemModel* localModel = index.model();
|
||||||
|
QString headerText = localModel->headerData(index.column(), Qt::Horizontal).toString();
|
||||||
|
|
||||||
|
const UserRoles role = GET_ROLE_FOR_COLUMN(index.column());
|
||||||
|
const bool isInt = INT_ROLES.contains(role);
|
||||||
|
if (isInt) {
|
||||||
|
int value = index.model()->data(index, Qt::EditRole).toInt();
|
||||||
|
// Put the value into the SpinBox
|
||||||
|
QSpinBox* spinbox = static_cast<QSpinBox*>(editor);
|
||||||
|
spinbox->setValue(value);
|
||||||
|
} else {
|
||||||
|
// Put the value into the SpinBox
|
||||||
|
qreal value = index.model()->data(index, Qt::EditRole).toReal();
|
||||||
|
QDoubleSpinBox* spinbox = static_cast<QDoubleSpinBox*>(editor);
|
||||||
|
spinbox->setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// QStyledItemDelegate::setEditorData(editor, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpinboxDelegate::setModelData(QWidget* editor,
|
||||||
|
QAbstractItemModel* model,
|
||||||
|
const QModelIndex& index) const {
|
||||||
|
QStyledItemDelegate::setModelData(editor, model, index);
|
||||||
|
}
|
||||||
27
widgets/controls/spinboxdelegate.h
Normal file
27
widgets/controls/spinboxdelegate.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef SPINBOXDELEGATE_H
|
||||||
|
#define SPINBOXDELEGATE_H
|
||||||
|
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
|
||||||
|
class SpinboxDelegate : public QStyledItemDelegate {
|
||||||
|
// TODO move source code files into subfolder "widgets/delegate"
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SpinboxDelegate(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
/// QAbstractItemDelegate interface
|
||||||
|
public:
|
||||||
|
void paint(QPainter* painter,
|
||||||
|
const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex& index) const override;
|
||||||
|
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||||
|
QWidget* createEditor(QWidget* parent,
|
||||||
|
const QStyleOptionViewItem& option,
|
||||||
|
const QModelIndex& index) const override;
|
||||||
|
void setEditorData(QWidget* editor, const QModelIndex& index) const override;
|
||||||
|
void setModelData(QWidget* editor,
|
||||||
|
QAbstractItemModel* model,
|
||||||
|
const QModelIndex& index) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SPINBOXDELEGATE_H
|
||||||
Reference in New Issue
Block a user