Merge "Merge remote-tracking branch 'origin/qds-1.59'"
11
README.md
@@ -439,6 +439,17 @@ we thank the authors who made this possible:
|
|||||||
Distributed under the Boost Software License, Version 1.0.
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
### Implementation for std::span
|
||||||
|
|
||||||
|
https://github.com/tcbrindle/span
|
||||||
|
|
||||||
|
QtCreator/src/libs/3rdparty/span
|
||||||
|
|
||||||
|
Copyright Tristan Brindle, 2018
|
||||||
|
|
||||||
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
|
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
### Open Source front-end for C++ (license MIT), enhanced for use in Qt Creator
|
### Open Source front-end for C++ (license MIT), enhanced for use in Qt Creator
|
||||||
|
|
||||||
Roberto Raggi <roberto.raggi@gmail.com>
|
Roberto Raggi <roberto.raggi@gmail.com>
|
||||||
|
@@ -182,6 +182,21 @@
|
|||||||
\li \l{https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/src/libs/3rdparty/variant}
|
\li \l{https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/src/libs/3rdparty/variant}
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
|
\li \b{Implementation for std::span}
|
||||||
|
|
||||||
|
Copyright Tristan Brindle, 2018
|
||||||
|
|
||||||
|
Distributed under the \l {http://boost.org/LICENSE_1_0.txt}
|
||||||
|
{Boost Software License, Version 1.0}.
|
||||||
|
(See accompanying file LICENSE.md.)
|
||||||
|
|
||||||
|
The source code can be found here:
|
||||||
|
\list
|
||||||
|
\li \l{https://github.com/tcbrindle/span}
|
||||||
|
\li QtCreator/src/libs/3rdparty/span
|
||||||
|
\li \l{https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/src/libs/3rdparty/span}
|
||||||
|
\endlist
|
||||||
|
|
||||||
\li \b{Open Source front-end for C++ (license MIT)}, enhanced for use
|
\li \b{Open Source front-end for C++ (license MIT)}, enhanced for use
|
||||||
in \QC.\br
|
in \QC.\br
|
||||||
Roberto Raggi <roberto.raggi@gmail.com>\br
|
Roberto Raggi <roberto.raggi@gmail.com>\br
|
||||||
|
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 11 KiB |
BIN
doc/qtdesignstudio/images/studio-3d-area-light.png
Normal file
After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 21 KiB |
BIN
doc/qtdesignstudio/images/studio-3d-spot-light.png
Normal file
After Width: | Height: | Size: 25 KiB |
@@ -42,6 +42,7 @@
|
|||||||
\list
|
\list
|
||||||
\li \l{DirectionalLight}{Light Directional}
|
\li \l{DirectionalLight}{Light Directional}
|
||||||
\li \l{PointLight}{Light Point}
|
\li \l{PointLight}{Light Point}
|
||||||
|
\li \l{SpotLight}{Light Spot}
|
||||||
\li \l{AreaLight}{Light Area}
|
\li \l{AreaLight}{Light Area}
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
@@ -121,6 +122,22 @@
|
|||||||
Aside from fade, a point light has the same properties as a directional
|
Aside from fade, a point light has the same properties as a directional
|
||||||
light.
|
light.
|
||||||
|
|
||||||
|
\section1 Spot Light
|
||||||
|
|
||||||
|
A spot light emits light towards one direction in a cone shape.
|
||||||
|
The light intensity diminishes when approaching the value of the
|
||||||
|
\uicontrol {Cone angle} property. The angle at which the light
|
||||||
|
intensity starts to diminish is defined by the
|
||||||
|
\uicontrol {Inner cone angle} property. Both angles are defined in degrees.
|
||||||
|
|
||||||
|
Inside the inner cone angle, the spot light behaves similarly to the point
|
||||||
|
light. There the light intensity diminishes according to inverse-square-law.
|
||||||
|
However, the fade-off (and range) can be controlled with the
|
||||||
|
\uicontrol {Constant fade}, \uicontrol {Linear fade}, and
|
||||||
|
\uicontrol {Quadratic fade} properties.
|
||||||
|
|
||||||
|
\image studio-3d-spot-light.png
|
||||||
|
|
||||||
\section1 Area Light
|
\section1 Area Light
|
||||||
|
|
||||||
An area light is similar to the directional light. However, instead of
|
An area light is similar to the directional light. However, instead of
|
||||||
@@ -135,7 +152,7 @@
|
|||||||
The image below shows an example on how to light an object with different
|
The image below shows an example on how to light an object with different
|
||||||
colors using two different area lights.
|
colors using two different area lights.
|
||||||
|
|
||||||
\image area-light.png
|
\image studio-3d-area-light.png
|
||||||
|
|
||||||
You can rotate, scale, and move area lights.
|
You can rotate, scale, and move area lights.
|
||||||
|
|
||||||
|
@@ -159,7 +159,7 @@
|
|||||||
an easy way to add a high-quality look at a relatively low cost.
|
an easy way to add a high-quality look at a relatively low cost.
|
||||||
|
|
||||||
To specify an image to use as the specular reflection map, set the
|
To specify an image to use as the specular reflection map, set the
|
||||||
\uicontrol {Light probe} property
|
\uicontrol {Light probe} property.
|
||||||
|
|
||||||
Crisp images cause your material to look very glossy. The more you
|
Crisp images cause your material to look very glossy. The more you
|
||||||
blur your image, the softer your material appears.
|
blur your image, the softer your material appears.
|
||||||
|
@@ -0,0 +1,47 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "changelanguagecommand.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
QDataStream &operator<<(QDataStream &out, const ChangeLanguageCommand &command)
|
||||||
|
{
|
||||||
|
return out << command.language;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream &operator>>(QDataStream &in, ChangeLanguageCommand &command)
|
||||||
|
{
|
||||||
|
return in >> command.language;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug debug, const ChangeLanguageCommand &command)
|
||||||
|
{
|
||||||
|
return debug.nospace() << "ChangeLanguageCommand(" << command.language << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,51 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class ChangeLanguageCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ChangeLanguageCommand() = default;
|
||||||
|
ChangeLanguageCommand(const QString &language)
|
||||||
|
: language(language)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend QDataStream &operator<<(QDataStream &out, const ChangeLanguageCommand &command);
|
||||||
|
friend QDataStream &operator>>(QDataStream &in, ChangeLanguageCommand &command);
|
||||||
|
friend QDebug operator<<(QDebug debug, const ChangeLanguageCommand &command);
|
||||||
|
|
||||||
|
public:
|
||||||
|
QString language;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QmlDesigner::ChangeLanguageCommand)
|
@@ -0,0 +1,46 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#include "changepreviewimagesizecommand.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
QDataStream &operator<<(QDataStream &out, const ChangePreviewImageSizeCommand &command)
|
||||||
|
{
|
||||||
|
return out << command.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream &operator>>(QDataStream &in, ChangePreviewImageSizeCommand &command)
|
||||||
|
{
|
||||||
|
return in >> command.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug debug, const ChangePreviewImageSizeCommand &command)
|
||||||
|
{
|
||||||
|
return debug.nospace() << "ChangePreviewImageSizeCommand(" << command.size << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,50 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QSize>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class ChangePreviewImageSizeCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ChangePreviewImageSizeCommand() = default;
|
||||||
|
ChangePreviewImageSizeCommand(const QSize &size)
|
||||||
|
: size(size)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend QDataStream &operator<<(QDataStream &out, const ChangePreviewImageSizeCommand &command);
|
||||||
|
friend QDataStream &operator>>(QDataStream &in, ChangePreviewImageSizeCommand &command);
|
||||||
|
friend QDebug operator<<(QDebug debug, const ChangePreviewImageSizeCommand &command);
|
||||||
|
|
||||||
|
public:
|
||||||
|
QSize size;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QmlDesigner::ChangePreviewImageSizeCommand)
|
@@ -1,6 +1,8 @@
|
|||||||
INCLUDEPATH += $$PWD/
|
INCLUDEPATH += $$PWD/
|
||||||
|
|
||||||
HEADERS += $$PWD/synchronizecommand.h
|
HEADERS += $$PWD/synchronizecommand.h
|
||||||
|
HEADERS += $$PWD/changepreviewimagesizecommand.h
|
||||||
|
HEADERS += $$PWD/changelanguagecommand.h
|
||||||
HEADERS += $$PWD//debugoutputcommand.h
|
HEADERS += $$PWD//debugoutputcommand.h
|
||||||
HEADERS += $$PWD/endpuppetcommand.h
|
HEADERS += $$PWD/endpuppetcommand.h
|
||||||
HEADERS += $$PWD/tokencommand.h
|
HEADERS += $$PWD/tokencommand.h
|
||||||
@@ -33,6 +35,8 @@ HEADERS += $$PWD/inputeventcommand.h
|
|||||||
HEADERS += $$PWD/view3dactioncommand.h
|
HEADERS += $$PWD/view3dactioncommand.h
|
||||||
|
|
||||||
SOURCES += $$PWD/synchronizecommand.cpp
|
SOURCES += $$PWD/synchronizecommand.cpp
|
||||||
|
SOURCES += $$PWD/changepreviewimagesizecommand.cpp
|
||||||
|
SOURCES += $$PWD/changelanguagecommand.cpp
|
||||||
SOURCES += $$PWD/debugoutputcommand.cpp
|
SOURCES += $$PWD/debugoutputcommand.cpp
|
||||||
SOURCES += $$PWD/endpuppetcommand.cpp
|
SOURCES += $$PWD/endpuppetcommand.cpp
|
||||||
SOURCES += $$PWD/tokencommand.cpp
|
SOURCES += $$PWD/tokencommand.cpp
|
||||||
|
@@ -35,43 +35,44 @@
|
|||||||
|
|
||||||
#include "nodeinstanceserverinterface.h"
|
#include "nodeinstanceserverinterface.h"
|
||||||
|
|
||||||
#include "propertyabstractcontainer.h"
|
#include "changeauxiliarycommand.h"
|
||||||
#include "propertyvaluecontainer.h"
|
#include "changebindingscommand.h"
|
||||||
#include "propertybindingcontainer.h"
|
#include "changefileurlcommand.h"
|
||||||
#include "instancecontainer.h"
|
#include "changeidscommand.h"
|
||||||
|
#include "changelanguagecommand.h"
|
||||||
|
#include "changenodesourcecommand.h"
|
||||||
|
#include "changepreviewimagesizecommand.h"
|
||||||
|
#include "changeselectioncommand.h"
|
||||||
|
#include "changestatecommand.h"
|
||||||
|
#include "changevaluescommand.h"
|
||||||
|
#include "childrenchangedcommand.h"
|
||||||
|
#include "clearscenecommand.h"
|
||||||
|
#include "completecomponentcommand.h"
|
||||||
|
#include "componentcompletedcommand.h"
|
||||||
#include "createinstancescommand.h"
|
#include "createinstancescommand.h"
|
||||||
#include "createscenecommand.h"
|
#include "createscenecommand.h"
|
||||||
#include "update3dviewstatecommand.h"
|
|
||||||
#include "changevaluescommand.h"
|
|
||||||
#include "changebindingscommand.h"
|
|
||||||
#include "changeauxiliarycommand.h"
|
|
||||||
#include "changefileurlcommand.h"
|
|
||||||
#include "removeinstancescommand.h"
|
|
||||||
#include "clearscenecommand.h"
|
|
||||||
#include "removepropertiescommand.h"
|
|
||||||
#include "reparentinstancescommand.h"
|
|
||||||
#include "changeidscommand.h"
|
|
||||||
#include "changestatecommand.h"
|
|
||||||
#include "completecomponentcommand.h"
|
|
||||||
#include "synchronizecommand.h"
|
|
||||||
#include "removesharedmemorycommand.h"
|
|
||||||
#include "tokencommand.h"
|
|
||||||
#include "inputeventcommand.h"
|
|
||||||
#include "view3dactioncommand.h"
|
|
||||||
|
|
||||||
#include "informationchangedcommand.h"
|
|
||||||
#include "pixmapchangedcommand.h"
|
|
||||||
#include "valueschangedcommand.h"
|
|
||||||
#include "childrenchangedcommand.h"
|
|
||||||
#include "imagecontainer.h"
|
|
||||||
#include "statepreviewimagechangedcommand.h"
|
|
||||||
#include "componentcompletedcommand.h"
|
|
||||||
#include "changenodesourcecommand.h"
|
|
||||||
#include "endpuppetcommand.h"
|
|
||||||
#include "debugoutputcommand.h"
|
#include "debugoutputcommand.h"
|
||||||
|
#include "endpuppetcommand.h"
|
||||||
|
#include "imagecontainer.h"
|
||||||
|
#include "informationchangedcommand.h"
|
||||||
|
#include "inputeventcommand.h"
|
||||||
|
#include "instancecontainer.h"
|
||||||
|
#include "pixmapchangedcommand.h"
|
||||||
|
#include "propertyabstractcontainer.h"
|
||||||
|
#include "propertybindingcontainer.h"
|
||||||
|
#include "propertyvaluecontainer.h"
|
||||||
#include "puppetalivecommand.h"
|
#include "puppetalivecommand.h"
|
||||||
#include "changeselectioncommand.h"
|
|
||||||
#include "puppettocreatorcommand.h"
|
#include "puppettocreatorcommand.h"
|
||||||
|
#include "removeinstancescommand.h"
|
||||||
|
#include "removepropertiescommand.h"
|
||||||
|
#include "removesharedmemorycommand.h"
|
||||||
|
#include "reparentinstancescommand.h"
|
||||||
|
#include "statepreviewimagechangedcommand.h"
|
||||||
|
#include "synchronizecommand.h"
|
||||||
|
#include "tokencommand.h"
|
||||||
|
#include "update3dviewstatecommand.h"
|
||||||
|
#include "valueschangedcommand.h"
|
||||||
|
#include "view3dactioncommand.h"
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
@@ -91,7 +92,7 @@ NodeInstanceClientProxy::NodeInstanceClientProxy(QObject *parent)
|
|||||||
m_synchronizeId(-1)
|
m_synchronizeId(-1)
|
||||||
{
|
{
|
||||||
connect(&m_puppetAliveTimer, &QTimer::timeout, this, &NodeInstanceClientProxy::sendPuppetAliveCommand);
|
connect(&m_puppetAliveTimer, &QTimer::timeout, this, &NodeInstanceClientProxy::sendPuppetAliveCommand);
|
||||||
m_puppetAliveTimer.setInterval(1000);
|
m_puppetAliveTimer.setInterval(2000);
|
||||||
m_puppetAliveTimer.start();
|
m_puppetAliveTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,6 +325,16 @@ void NodeInstanceClientProxy::view3DAction(const View3DActionCommand &command)
|
|||||||
nodeInstanceServer()->view3DAction(command);
|
nodeInstanceServer()->view3DAction(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeInstanceClientProxy::changeLanguage(const ChangeLanguageCommand &command)
|
||||||
|
{
|
||||||
|
nodeInstanceServer()->changeLanguage(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeInstanceClientProxy::changePreviewImageSize(const ChangePreviewImageSizeCommand &command)
|
||||||
|
{
|
||||||
|
nodeInstanceServer()->changePreviewImageSize(command);
|
||||||
|
}
|
||||||
|
|
||||||
void NodeInstanceClientProxy::readDataStream()
|
void NodeInstanceClientProxy::readDataStream()
|
||||||
{
|
{
|
||||||
QList<QVariant> commandList;
|
QList<QVariant> commandList;
|
||||||
@@ -490,6 +501,9 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command)
|
|||||||
static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand");
|
static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand");
|
||||||
static const int inputEventCommandType = QMetaType::type("InputEventCommand");
|
static const int inputEventCommandType = QMetaType::type("InputEventCommand");
|
||||||
static const int view3DActionCommandType = QMetaType::type("View3DActionCommand");
|
static const int view3DActionCommandType = QMetaType::type("View3DActionCommand");
|
||||||
|
static const int changeLanguageCommand = QMetaType::type("ChangeLanguageCommand");
|
||||||
|
static const int changePreviewImageSizeCommand = QMetaType::type(
|
||||||
|
"ChangePreviewImageSizeCommand");
|
||||||
|
|
||||||
const int commandType = command.userType();
|
const int commandType = command.userType();
|
||||||
|
|
||||||
@@ -539,6 +553,10 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command)
|
|||||||
} else if (commandType == changeSelectionCommandType) {
|
} else if (commandType == changeSelectionCommandType) {
|
||||||
ChangeSelectionCommand changeSelectionCommand = command.value<ChangeSelectionCommand>();
|
ChangeSelectionCommand changeSelectionCommand = command.value<ChangeSelectionCommand>();
|
||||||
changeSelection(changeSelectionCommand);
|
changeSelection(changeSelectionCommand);
|
||||||
|
} else if (command.userType() == changeLanguageCommand) {
|
||||||
|
changeLanguage(command.value<ChangeLanguageCommand>());
|
||||||
|
} else if (command.userType() == changePreviewImageSizeCommand) {
|
||||||
|
changePreviewImageSize(command.value<ChangePreviewImageSizeCommand>());
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
@@ -61,6 +61,8 @@ class ChangeSelectionCommand;
|
|||||||
class PuppetToCreatorCommand;
|
class PuppetToCreatorCommand;
|
||||||
class InputEventCommand;
|
class InputEventCommand;
|
||||||
class View3DActionCommand;
|
class View3DActionCommand;
|
||||||
|
class ChangeLanguageCommand;
|
||||||
|
class ChangePreviewImageSizeCommand;
|
||||||
|
|
||||||
class NodeInstanceClientProxy : public QObject, public NodeInstanceClientInterface
|
class NodeInstanceClientProxy : public QObject, public NodeInstanceClientInterface
|
||||||
{
|
{
|
||||||
@@ -116,6 +118,8 @@ protected:
|
|||||||
static QVariant readCommandFromIOStream(QIODevice *ioDevice, quint32 *readCommandCounter, quint32 *blockSize);
|
static QVariant readCommandFromIOStream(QIODevice *ioDevice, quint32 *readCommandCounter, quint32 *blockSize);
|
||||||
void inputEvent(const InputEventCommand &command);
|
void inputEvent(const InputEventCommand &command);
|
||||||
void view3DAction(const View3DActionCommand &command);
|
void view3DAction(const View3DActionCommand &command);
|
||||||
|
void changeLanguage(const ChangeLanguageCommand &command);
|
||||||
|
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void readDataStream();
|
void readDataStream();
|
||||||
|
@@ -26,44 +26,45 @@
|
|||||||
#include "nodeinstanceserverinterface.h"
|
#include "nodeinstanceserverinterface.h"
|
||||||
#include <qmetatype.h>
|
#include <qmetatype.h>
|
||||||
|
|
||||||
#include "propertyabstractcontainer.h"
|
|
||||||
#include "propertyvaluecontainer.h"
|
|
||||||
#include "propertybindingcontainer.h"
|
|
||||||
#include "instancecontainer.h"
|
|
||||||
#include "createinstancescommand.h"
|
|
||||||
#include "createscenecommand.h"
|
|
||||||
#include "update3dviewstatecommand.h"
|
|
||||||
#include "changevaluescommand.h"
|
|
||||||
#include "changebindingscommand.h"
|
|
||||||
#include "changeauxiliarycommand.h"
|
|
||||||
#include "changefileurlcommand.h"
|
|
||||||
#include "removeinstancescommand.h"
|
|
||||||
#include "clearscenecommand.h"
|
|
||||||
#include "removepropertiescommand.h"
|
|
||||||
#include "reparentinstancescommand.h"
|
|
||||||
#include "changeidscommand.h"
|
|
||||||
#include "changestatecommand.h"
|
|
||||||
#include "completecomponentcommand.h"
|
|
||||||
#include "addimportcontainer.h"
|
#include "addimportcontainer.h"
|
||||||
|
#include "changeauxiliarycommand.h"
|
||||||
|
#include "changebindingscommand.h"
|
||||||
|
#include "changefileurlcommand.h"
|
||||||
|
#include "changeidscommand.h"
|
||||||
|
#include "changelanguagecommand.h"
|
||||||
#include "changenodesourcecommand.h"
|
#include "changenodesourcecommand.h"
|
||||||
#include "changeselectioncommand.h"
|
#include "changeselectioncommand.h"
|
||||||
#include "inputeventcommand.h"
|
#include "changestatecommand.h"
|
||||||
#include "view3dactioncommand.h"
|
#include "changevaluescommand.h"
|
||||||
|
#include "changepreviewimagesizecommand.h"
|
||||||
#include "informationchangedcommand.h"
|
|
||||||
#include "pixmapchangedcommand.h"
|
|
||||||
#include "valueschangedcommand.h"
|
|
||||||
#include "childrenchangedcommand.h"
|
#include "childrenchangedcommand.h"
|
||||||
#include "imagecontainer.h"
|
#include "clearscenecommand.h"
|
||||||
#include "statepreviewimagechangedcommand.h"
|
#include "completecomponentcommand.h"
|
||||||
#include "componentcompletedcommand.h"
|
#include "componentcompletedcommand.h"
|
||||||
#include "synchronizecommand.h"
|
#include "createinstancescommand.h"
|
||||||
#include "tokencommand.h"
|
#include "createscenecommand.h"
|
||||||
#include "removesharedmemorycommand.h"
|
|
||||||
#include "endpuppetcommand.h"
|
|
||||||
#include "debugoutputcommand.h"
|
#include "debugoutputcommand.h"
|
||||||
|
#include "endpuppetcommand.h"
|
||||||
|
#include "imagecontainer.h"
|
||||||
|
#include "informationchangedcommand.h"
|
||||||
|
#include "inputeventcommand.h"
|
||||||
|
#include "instancecontainer.h"
|
||||||
|
#include "pixmapchangedcommand.h"
|
||||||
|
#include "propertyabstractcontainer.h"
|
||||||
|
#include "propertybindingcontainer.h"
|
||||||
|
#include "propertyvaluecontainer.h"
|
||||||
#include "puppetalivecommand.h"
|
#include "puppetalivecommand.h"
|
||||||
#include "puppettocreatorcommand.h"
|
#include "puppettocreatorcommand.h"
|
||||||
|
#include "removeinstancescommand.h"
|
||||||
|
#include "removepropertiescommand.h"
|
||||||
|
#include "removesharedmemorycommand.h"
|
||||||
|
#include "reparentinstancescommand.h"
|
||||||
|
#include "statepreviewimagechangedcommand.h"
|
||||||
|
#include "synchronizecommand.h"
|
||||||
|
#include "tokencommand.h"
|
||||||
|
#include "update3dviewstatecommand.h"
|
||||||
|
#include "valueschangedcommand.h"
|
||||||
|
#include "view3dactioncommand.h"
|
||||||
|
|
||||||
#include <enumeration.h>
|
#include <enumeration.h>
|
||||||
|
|
||||||
@@ -212,6 +213,12 @@ void NodeInstanceServerInterface::registerCommands()
|
|||||||
|
|
||||||
qRegisterMetaType<QPair<int, int>>("QPairIntInt");
|
qRegisterMetaType<QPair<int, int>>("QPairIntInt");
|
||||||
qRegisterMetaTypeStreamOperators<QPair<int, int>>("QPairIntInt");
|
qRegisterMetaTypeStreamOperators<QPair<int, int>>("QPairIntInt");
|
||||||
|
|
||||||
|
qRegisterMetaType<ChangeLanguageCommand>("ChangeLanguageCommand");
|
||||||
|
qRegisterMetaTypeStreamOperators<ChangeLanguageCommand>("ChangeLanguageCommand");
|
||||||
|
|
||||||
|
qRegisterMetaType<ChangePreviewImageSizeCommand>("ChangePreviewImageSizeCommand");
|
||||||
|
qRegisterMetaTypeStreamOperators<ChangePreviewImageSizeCommand>("ChangePreviewImageSizeCommand");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -53,6 +53,8 @@ class RemoveSharedMemoryCommand;
|
|||||||
class ChangeSelectionCommand;
|
class ChangeSelectionCommand;
|
||||||
class InputEventCommand;
|
class InputEventCommand;
|
||||||
class View3DActionCommand;
|
class View3DActionCommand;
|
||||||
|
class ChangeLanguageCommand;
|
||||||
|
class ChangePreviewImageSizeCommand;
|
||||||
|
|
||||||
class NodeInstanceServerInterface : public QObject
|
class NodeInstanceServerInterface : public QObject
|
||||||
{
|
{
|
||||||
@@ -85,9 +87,10 @@ public:
|
|||||||
virtual void changeSelection(const ChangeSelectionCommand &command) = 0;
|
virtual void changeSelection(const ChangeSelectionCommand &command) = 0;
|
||||||
virtual void inputEvent(const InputEventCommand &command) = 0;
|
virtual void inputEvent(const InputEventCommand &command) = 0;
|
||||||
virtual void view3DAction(const View3DActionCommand &command) = 0;
|
virtual void view3DAction(const View3DActionCommand &command) = 0;
|
||||||
|
virtual void changeLanguage(const ChangeLanguageCommand &command) = 0;
|
||||||
|
virtual void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) = 0;
|
||||||
|
|
||||||
virtual void benchmark(const QString &)
|
virtual void benchmark(const QString &) {}
|
||||||
{}
|
|
||||||
|
|
||||||
static void registerCommands();
|
static void registerCommands();
|
||||||
};
|
};
|
||||||
|
@@ -69,6 +69,7 @@
|
|||||||
#include <changeselectioncommand.h>
|
#include <changeselectioncommand.h>
|
||||||
#include <inputeventcommand.h>
|
#include <inputeventcommand.h>
|
||||||
#include <view3dactioncommand.h>
|
#include <view3dactioncommand.h>
|
||||||
|
#include <changelanguagecommand.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
@@ -1397,7 +1398,22 @@ void NodeInstanceServer::view3DAction(const View3DActionCommand &command)
|
|||||||
Q_UNUSED(command)
|
Q_UNUSED(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeInstanceServer::changeLanguage(const ChangeLanguageCommand &command)
|
||||||
|
{
|
||||||
|
static QPointer<MultiLanguage::Translator> multilanguageTranslator;
|
||||||
|
if (!MultiLanguage::databaseFilePath().isEmpty()) {
|
||||||
|
if (!multilanguageLink) {
|
||||||
|
multilanguageLink = std::make_unique<MultiLanguage::Link>();
|
||||||
|
multilanguageTranslator = multilanguageLink->translator().release();
|
||||||
|
QCoreApplication::installTranslator(multilanguageTranslator);
|
||||||
|
}
|
||||||
|
if (multilanguageTranslator)
|
||||||
|
multilanguageTranslator->setLanguage(command.language);
|
||||||
|
}
|
||||||
|
QEvent ev(QEvent::LanguageChange);
|
||||||
|
QCoreApplication::sendEvent(QCoreApplication::instance(), &ev);
|
||||||
|
engine()->retranslate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeInstanceServer::changePreviewImageSize(const ChangePreviewImageSizeCommand &) {}
|
||||||
|
} // namespace QmlDesigner
|
||||||
|
@@ -25,12 +25,20 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
|
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
|
||||||
|
#include <multilanguagelink.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QTranslator>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <nodeinstanceserverinterface.h>
|
#include <nodeinstanceserverinterface.h>
|
||||||
#include "servernodeinstance.h"
|
#include "servernodeinstance.h"
|
||||||
#include "debugoutputcommand.h"
|
#include "debugoutputcommand.h"
|
||||||
@@ -47,6 +55,37 @@ QList<T>toList(const QSet<T> &set)
|
|||||||
}
|
}
|
||||||
} //QtHelpers
|
} //QtHelpers
|
||||||
|
|
||||||
|
#ifndef MULTILANGUAGE_TRANSLATIONPROVIDER
|
||||||
|
namespace MultiLanguage {
|
||||||
|
static QByteArray databaseFilePath()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
class Translator : public QTranslator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void setLanguage(const QString&) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Link
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Link()
|
||||||
|
{
|
||||||
|
if (qEnvironmentVariableIsSet("QT_MULTILANGUAGE_DATABASE"))
|
||||||
|
qWarning() << "QT_MULTILANGUAGE_DATABASE is set but QQmlDebugTranslationService is without MULTILANGUAGE_TRANSLATIONPROVIDER support compiled.";
|
||||||
|
}
|
||||||
|
std::unique_ptr<MultiLanguage::Translator> translator() {
|
||||||
|
//should never be called
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return std::make_unique<MultiLanguage::Translator>();
|
||||||
|
}
|
||||||
|
const bool isActivated = false;
|
||||||
|
};
|
||||||
|
} //namespace MultiLanguage
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QFileSystemWatcher;
|
class QFileSystemWatcher;
|
||||||
class QQmlView;
|
class QQmlView;
|
||||||
@@ -112,6 +151,8 @@ public:
|
|||||||
void changeSelection(const ChangeSelectionCommand &command) override;
|
void changeSelection(const ChangeSelectionCommand &command) override;
|
||||||
void inputEvent(const InputEventCommand &command) override;
|
void inputEvent(const InputEventCommand &command) override;
|
||||||
void view3DAction(const View3DActionCommand &command) override;
|
void view3DAction(const View3DActionCommand &command) override;
|
||||||
|
void changeLanguage(const ChangeLanguageCommand &command) override;
|
||||||
|
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override;
|
||||||
|
|
||||||
ServerNodeInstance instanceForId(qint32 id) const;
|
ServerNodeInstance instanceForId(qint32 id) const;
|
||||||
bool hasInstanceForId(qint32 id) const;
|
bool hasInstanceForId(qint32 id) const;
|
||||||
@@ -248,6 +289,7 @@ private:
|
|||||||
QPointer<QObject> m_dummyContextObject;
|
QPointer<QObject> m_dummyContextObject;
|
||||||
QPointer<QQmlComponent> m_importComponent;
|
QPointer<QQmlComponent> m_importComponent;
|
||||||
QPointer<QObject> m_importComponentObject;
|
QPointer<QObject> m_importComponentObject;
|
||||||
|
std::unique_ptr<MultiLanguage::Link> multilanguageLink;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -768,6 +768,8 @@ QObject *ObjectNodeInstance::createComponent(const QString &componentPath, QQmlC
|
|||||||
qWarning() << error;
|
qWarning() << error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object->setProperty("__designer_url__", QUrl::fromLocalFile(componentPath));
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,10 +25,12 @@
|
|||||||
|
|
||||||
#include "qt5previewnodeinstanceserver.h"
|
#include "qt5previewnodeinstanceserver.h"
|
||||||
|
|
||||||
#include "nodeinstanceclientinterface.h"
|
#include "changepreviewimagesizecommand.h"
|
||||||
#include "statepreviewimagechangedcommand.h"
|
|
||||||
#include "createscenecommand.h"
|
#include "createscenecommand.h"
|
||||||
|
#include "nodeinstanceclientinterface.h"
|
||||||
#include "removesharedmemorycommand.h"
|
#include "removesharedmemorycommand.h"
|
||||||
|
#include "statepreviewimagechangedcommand.h"
|
||||||
|
|
||||||
#include <QQuickView>
|
#include <QQuickView>
|
||||||
#include <QQuickItem>
|
#include <QQuickItem>
|
||||||
#include <designersupportdelegate.h>
|
#include <designersupportdelegate.h>
|
||||||
@@ -100,7 +102,9 @@ QImage Qt5PreviewNodeInstanceServer::renderPreviewImage()
|
|||||||
QRectF boundingRect = rootNodeInstance().boundingRect();
|
QRectF boundingRect = rootNodeInstance().boundingRect();
|
||||||
|
|
||||||
QSize previewImageSize = boundingRect.size().toSize();
|
QSize previewImageSize = boundingRect.size().toSize();
|
||||||
previewImageSize.scale(QSize(160, 160), Qt::KeepAspectRatio);
|
|
||||||
|
if (!m_previewSize.isNull())
|
||||||
|
previewImageSize.scale(m_previewSize, Qt::KeepAspectRatio);
|
||||||
|
|
||||||
QImage previewImage = rootNodeInstance().renderPreviewImage(previewImageSize);
|
QImage previewImage = rootNodeInstance().renderPreviewImage(previewImageSize);
|
||||||
|
|
||||||
@@ -113,4 +117,15 @@ void QmlDesigner::Qt5PreviewNodeInstanceServer::removeSharedMemory(const QmlDesi
|
|||||||
ImageContainer::removeSharedMemorys(command.keyNumbers());
|
ImageContainer::removeSharedMemorys(command.keyNumbers());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Qt5PreviewNodeInstanceServer::changePreviewImageSize(
|
||||||
|
const ChangePreviewImageSizeCommand &command)
|
||||||
|
{
|
||||||
|
m_previewSize = command.size;
|
||||||
|
|
||||||
|
if (!command.size.isValid())
|
||||||
|
m_previewSize = {160, 160};
|
||||||
|
|
||||||
|
collectItemChangesAndSendChangeCommands();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -38,6 +38,7 @@ public:
|
|||||||
void createScene(const CreateSceneCommand &command) override;
|
void createScene(const CreateSceneCommand &command) override;
|
||||||
void changeState(const ChangeStateCommand &command) override;
|
void changeState(const ChangeStateCommand &command) override;
|
||||||
void removeSharedMemory(const RemoveSharedMemoryCommand &command) override;
|
void removeSharedMemory(const RemoveSharedMemoryCommand &command) override;
|
||||||
|
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override;
|
||||||
|
|
||||||
QImage renderPreviewImage();
|
QImage renderPreviewImage();
|
||||||
|
|
||||||
@@ -47,6 +48,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ServerNodeInstance m_currentState;
|
ServerNodeInstance m_currentState;
|
||||||
|
QSize m_previewSize{160, 160};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -5,6 +5,13 @@ CONFIG += c++11
|
|||||||
|
|
||||||
DEFINES -= QT_CREATOR
|
DEFINES -= QT_CREATOR
|
||||||
|
|
||||||
|
# This .pri file contains classes to enable a special multilanguage translator debug service
|
||||||
|
MULTILANGUAGE_SUPPORT_PRI=$$(MULTILANGUAGE_SUPPORT_PRI)
|
||||||
|
!isEmpty(MULTILANGUAGE_SUPPORT_PRI) {
|
||||||
|
include($$(MULTILANGUAGE_SUPPORT_PRI))
|
||||||
|
DEFINES += MULTILANGUAGE_TRANSLATIONPROVIDER
|
||||||
|
}
|
||||||
|
|
||||||
include (editor3d/editor3d.pri)
|
include (editor3d/editor3d.pri)
|
||||||
include (../instances/instances.pri)
|
include (../instances/instances.pri)
|
||||||
include (instances/instances.pri)
|
include (instances/instances.pri)
|
||||||
|
@@ -26,6 +26,8 @@
|
|||||||
import HelperWidgets 2.0
|
import HelperWidgets 2.0
|
||||||
import QtQuick 2.1
|
import QtQuick 2.1
|
||||||
import QtQuick.Layouts 1.1
|
import QtQuick.Layouts 1.1
|
||||||
|
import StudioTheme 1.0 as StudioTheme
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
id: section
|
id: section
|
||||||
caption: qsTr("Animation")
|
caption: qsTr("Animation")
|
||||||
@@ -33,6 +35,7 @@ Section {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
property bool showDuration: true
|
property bool showDuration: true
|
||||||
|
property bool showEasingCurve: false
|
||||||
|
|
||||||
SectionLayout {
|
SectionLayout {
|
||||||
Label {
|
Label {
|
||||||
@@ -100,5 +103,22 @@ Section {
|
|||||||
text: backendValues.alwaysRunToEnd.valueToString
|
text: backendValues.alwaysRunToEnd.valueToString
|
||||||
backendValue: backendValues.alwaysRunToEnd
|
backendValue: backendValues.alwaysRunToEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
visible: section.showEasingCurve
|
||||||
|
text: qsTr("Easing Curve")
|
||||||
|
tooltip: qsTr("Define custom easing curve")
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolButtonRowButton {
|
||||||
|
visible: section.showEasingCurve
|
||||||
|
buttonIcon: StudioTheme.Constants.curveDesigner
|
||||||
|
EasingCurveEditor {
|
||||||
|
id: easingCurveEditor
|
||||||
|
modelNodeBackendProperty: modelNodeBackend
|
||||||
|
}
|
||||||
|
onClicked: easingCurveEditor.runDialog()
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -57,6 +57,7 @@ Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AnimationSection {
|
AnimationSection {
|
||||||
|
showEasingCurve: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -325,13 +325,11 @@ Rectangle {
|
|||||||
frameVisible: false
|
frameVisible: false
|
||||||
|
|
||||||
id: tabView
|
id: tabView
|
||||||
height: Math.max(layoutSectionHeight, specficsHeight)
|
height: Math.max(layoutSectionHeight, specficsHeight, advancedHeight) + extraHeight
|
||||||
|
|
||||||
property int layoutSectionHeight: 400
|
property int advancedHeight: 0
|
||||||
property int specficsOneHeight: 0
|
property int layoutSectionHeight: 0
|
||||||
property int specficsTwoHeight: 0
|
property int specficsHeight: 0
|
||||||
|
|
||||||
property int specficsHeight: Math.max(specficsOneHeight, specficsTwoHeight)
|
|
||||||
|
|
||||||
property int extraHeight: 40
|
property int extraHeight: 40
|
||||||
|
|
||||||
@@ -341,6 +339,9 @@ Rectangle {
|
|||||||
component: Column {
|
component: Column {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
onImplicitHeightChanged: tabView.specficsHeight = implicitHeight
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
@@ -355,13 +356,6 @@ Rectangle {
|
|||||||
active = false
|
active = false
|
||||||
active = true
|
active = true
|
||||||
}
|
}
|
||||||
|
|
||||||
property int loaderHeight: specificsTwo.item.height + tabView.extraHeight
|
|
||||||
onLoaderHeightChanged: tabView.specficsTwoHeight = loaderHeight
|
|
||||||
|
|
||||||
onLoaded: {
|
|
||||||
tabView.specficsTwoHeight = loaderHeight
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
@@ -387,11 +381,9 @@ Rectangle {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
onImplicitHeightChanged: tabView.layoutSectionHeight = implicitHeight
|
||||||
|
|
||||||
LayoutSection {
|
LayoutSection {
|
||||||
property int childRectHeight: childrenRect.height
|
|
||||||
onChildRectHeightChanged: {
|
|
||||||
tabView.layoutSectionHeight = childRectHeight + tabView.extraHeight
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MarginSection {
|
MarginSection {
|
||||||
@@ -720,6 +712,9 @@ Rectangle {
|
|||||||
component: Column {
|
component: Column {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
onImplicitHeightChanged: tabView.advancedHeight = implicitHeight
|
||||||
|
|
||||||
AdvancedSection {
|
AdvancedSection {
|
||||||
}
|
}
|
||||||
LayerSection {
|
LayerSection {
|
||||||
|
@@ -79,6 +79,7 @@ Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AnimationSection {
|
AnimationSection {
|
||||||
|
showEasingCurve: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -35,6 +35,7 @@ Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AnimationSection {
|
AnimationSection {
|
||||||
|
showEasingCurve: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -163,4 +163,9 @@ StudioControls.ComboBox {
|
|||||||
colorLogic.invalidate()
|
colorLogic.invalidate()
|
||||||
comboBox.__isCompleted = true
|
comboBox.__isCompleted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: modelNodeBackend
|
||||||
|
onSelectionToBeChanged: comboBox.popup.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -193,7 +193,7 @@ Section {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
backendValue: getBackendValue("styleName")
|
backendValue: getBackendValue("styleName")
|
||||||
model: styleNamesForFamily(fontComboBox.familyName)
|
model: styleNamesForFamily(fontComboBox.familyName)
|
||||||
useString: true
|
valueType: ComboBox.String
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
@@ -36,9 +36,11 @@ ButtonRow {
|
|||||||
property alias checked: myAbstractButton.checked
|
property alias checked: myAbstractButton.checked
|
||||||
|
|
||||||
signal onCheckedChanged()
|
signal onCheckedChanged()
|
||||||
|
signal clicked
|
||||||
|
|
||||||
AbstractButton {
|
AbstractButton {
|
||||||
id: myAbstractButton
|
id: myAbstractButton
|
||||||
onCheckedChanged: myButtonRow.onCheckedChanged()
|
onCheckedChanged: myButtonRow.onCheckedChanged()
|
||||||
|
onClicked: myButtonRow.clicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -48,67 +48,73 @@ QtObject {
|
|||||||
readonly property string adsClose: "\u0029"
|
readonly property string adsClose: "\u0029"
|
||||||
readonly property string adsDetach: "\u002A"
|
readonly property string adsDetach: "\u002A"
|
||||||
readonly property string adsDropDown: "\u002B"
|
readonly property string adsDropDown: "\u002B"
|
||||||
readonly property string alignBottom: "\u002C"
|
readonly property string aliasAnimated: "\u002C"
|
||||||
readonly property string alignCenterHorizontal: "\u002D"
|
readonly property string aliasProperty: "\u002D"
|
||||||
readonly property string alignCenterVertical: "\u002E"
|
readonly property string alignBottom: "\u002E"
|
||||||
readonly property string alignLeft: "\u002F"
|
readonly property string alignCenterHorizontal: "\u002F"
|
||||||
readonly property string alignRight: "\u0030"
|
readonly property string alignCenterVertical: "\u0030"
|
||||||
readonly property string alignTo: "\u0031"
|
readonly property string alignLeft: "\u0031"
|
||||||
readonly property string alignTop: "\u0032"
|
readonly property string alignRight: "\u0032"
|
||||||
readonly property string anchorBaseline: "\u0033"
|
readonly property string alignTo: "\u0033"
|
||||||
readonly property string anchorBottom: "\u0034"
|
readonly property string alignTop: "\u0034"
|
||||||
readonly property string anchorFill: "\u0035"
|
readonly property string anchorBaseline: "\u0035"
|
||||||
readonly property string anchorLeft: "\u0036"
|
readonly property string anchorBottom: "\u0036"
|
||||||
readonly property string anchorRight: "\u0037"
|
readonly property string anchorFill: "\u0037"
|
||||||
readonly property string anchorTop: "\u0038"
|
readonly property string anchorLeft: "\u0038"
|
||||||
readonly property string annotationBubble: "\u0039"
|
readonly property string anchorRight: "\u0039"
|
||||||
readonly property string annotationDecal: "\u003A"
|
readonly property string anchorTop: "\u003A"
|
||||||
readonly property string centerHorizontal: "\u003B"
|
readonly property string animatedProperty: "\u003B"
|
||||||
readonly property string centerVertical: "\u003C"
|
readonly property string annotationBubble: "\u003C"
|
||||||
readonly property string closeCross: "\u003D"
|
readonly property string annotationDecal: "\u003D"
|
||||||
readonly property string decisionNode: "\u003E"
|
readonly property string assign: "\u003E"
|
||||||
readonly property string deleteColumn: "\u003F"
|
readonly property string centerHorizontal: "\u003F"
|
||||||
readonly property string deleteRow: "\u0040"
|
readonly property string centerVertical: "\u0040"
|
||||||
readonly property string deleteTable: "\u0041"
|
readonly property string closeCross: "\u0041"
|
||||||
readonly property string detach: "\u0042"
|
readonly property string curveDesigner: "\u0042"
|
||||||
readonly property string distributeBottom: "\u0043"
|
readonly property string curveEditor: "\u0043"
|
||||||
readonly property string distributeCenterHorizontal: "\u0044"
|
readonly property string decisionNode: "\u0044"
|
||||||
readonly property string distributeCenterVertical: "\u0045"
|
readonly property string deleteColumn: "\u0045"
|
||||||
readonly property string distributeLeft: "\u0046"
|
readonly property string deleteRow: "\u0046"
|
||||||
readonly property string distributeOriginBottomRight: "\u0047"
|
readonly property string deleteTable: "\u0047"
|
||||||
readonly property string distributeOriginCenter: "\u0048"
|
readonly property string detach: "\u0048"
|
||||||
readonly property string distributeOriginNone: "\u0049"
|
readonly property string distributeBottom: "\u0049"
|
||||||
readonly property string distributeOriginTopLeft: "\u004A"
|
readonly property string distributeCenterHorizontal: "\u004A"
|
||||||
readonly property string distributeRight: "\u004B"
|
readonly property string distributeCenterVertical: "\u004B"
|
||||||
readonly property string distributeSpacingHorizontal: "\u004C"
|
readonly property string distributeLeft: "\u004C"
|
||||||
readonly property string distributeSpacingVertical: "\u004D"
|
readonly property string distributeOriginBottomRight: "\u004D"
|
||||||
readonly property string distributeTop: "\u004E"
|
readonly property string distributeOriginCenter: "\u004E"
|
||||||
readonly property string edit: "\u004F"
|
readonly property string distributeOriginNone: "\u004F"
|
||||||
readonly property string fontStyleBold: "\u0050"
|
readonly property string distributeOriginTopLeft: "\u0050"
|
||||||
readonly property string fontStyleItalic: "\u0051"
|
readonly property string distributeRight: "\u0051"
|
||||||
readonly property string fontStyleStrikethrough: "\u0052"
|
readonly property string distributeSpacingHorizontal: "\u0052"
|
||||||
readonly property string fontStyleUnderline: "\u0053"
|
readonly property string distributeSpacingVertical: "\u0053"
|
||||||
readonly property string mergeCells: "\u0054"
|
readonly property string distributeTop: "\u0054"
|
||||||
readonly property string redo: "\u0055"
|
readonly property string edit: "\u0055"
|
||||||
readonly property string splitColumns: "\u0056"
|
readonly property string fontStyleBold: "\u0056"
|
||||||
readonly property string splitRows: "\u0057"
|
readonly property string fontStyleItalic: "\u0057"
|
||||||
readonly property string startNode: "\u0058"
|
readonly property string fontStyleStrikethrough: "\u0058"
|
||||||
readonly property string testIcon: "\u0059"
|
readonly property string fontStyleUnderline: "\u0059"
|
||||||
readonly property string textAlignBottom: "\u005A"
|
readonly property string mergeCells: "\u005A"
|
||||||
readonly property string textAlignCenter: "\u005B"
|
readonly property string redo: "\u005B"
|
||||||
readonly property string textAlignLeft: "\u005C"
|
readonly property string splitColumns: "\u005C"
|
||||||
readonly property string textAlignMiddle: "\u005D"
|
readonly property string splitRows: "\u005D"
|
||||||
readonly property string textAlignRight: "\u005E"
|
readonly property string startNode: "\u005E"
|
||||||
readonly property string textAlignTop: "\u005F"
|
readonly property string testIcon: "\u005F"
|
||||||
readonly property string textBulletList: "\u0060"
|
readonly property string textAlignBottom: "\u0060"
|
||||||
readonly property string textFullJustification: "\u0061"
|
readonly property string textAlignCenter: "\u0061"
|
||||||
readonly property string textNumberedList: "\u0062"
|
readonly property string textAlignLeft: "\u0062"
|
||||||
readonly property string tickIcon: "\u0063"
|
readonly property string textAlignMiddle: "\u0063"
|
||||||
readonly property string triState: "\u0064"
|
readonly property string textAlignRight: "\u0064"
|
||||||
readonly property string undo: "\u0065"
|
readonly property string textAlignTop: "\u0065"
|
||||||
readonly property string upDownIcon: "\u0066"
|
readonly property string textBulletList: "\u0066"
|
||||||
readonly property string upDownSquare2: "\u0067"
|
readonly property string textFullJustification: "\u0067"
|
||||||
readonly property string wildcard: "\u0068"
|
readonly property string textNumberedList: "\u0068"
|
||||||
|
readonly property string tickIcon: "\u0069"
|
||||||
|
readonly property string triState: "\u006A"
|
||||||
|
readonly property string undo: "\u006B"
|
||||||
|
readonly property string upDownIcon: "\u006C"
|
||||||
|
readonly property string upDownSquare2: "\u006D"
|
||||||
|
readonly property string wildcard: "\u006E"
|
||||||
|
|
||||||
readonly property font iconFont: Qt.font({
|
readonly property font iconFont: Qt.font({
|
||||||
"family": controlIcons.name,
|
"family": controlIcons.name,
|
||||||
|
23
src/libs/3rdparty/span/LICENSE_1_0.txt
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
118
src/libs/3rdparty/span/README.md
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
|
||||||
|
[](https://en.wikipedia.org/wiki/C%2B%2B#Standardization)
|
||||||
|
[](http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
[](https://travis-ci.org/tcbrindle/span)
|
||||||
|
[](https://ci.appveyor.com/project/tcbrindle/span/branch/master)
|
||||||
|
[](https://godbolt.org/z/-vlZZR)
|
||||||
|
|
||||||
|
`std::span` implementation for C++11 and later
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
This repository contains a single-header implementation of C++20's `std::span`,
|
||||||
|
conforming to the C++20 committee draft.
|
||||||
|
It is compatible with C++11, but will use newer language features if they
|
||||||
|
are available.
|
||||||
|
|
||||||
|
It differs from the implementation in the [Microsoft GSL](https://github.com/Microsoft/GSL/)
|
||||||
|
in that it is single-header and does not depend on any other GSL facilities. It
|
||||||
|
also works with C++11, while the GSL version requires C++14.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
The recommended way to use the implementation simply copy the file `span.hpp`
|
||||||
|
from `include/tcb/` into your own sources and `#include` it like
|
||||||
|
any other header. By default, it lives in namespace `tcb`, but this can be
|
||||||
|
customised by setting the macro `TCB_SPAN_NAMESPACE_NAME` to an appropriate string
|
||||||
|
before `#include`-ing the header -- or simply edit the source code.
|
||||||
|
|
||||||
|
The rest of the repository contains testing machinery, and is not required for
|
||||||
|
use.
|
||||||
|
|
||||||
|
Compatibility
|
||||||
|
-------------
|
||||||
|
|
||||||
|
This implementation requires a conforming C++11 (or later) compiler, and is tested as far
|
||||||
|
back as GCC 5, Clang 3.5 and MSVC 2015 Update 3. Older compilers may work, but this is not guaranteed.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Documentation for `std::span` is available [on cppreference](https://en.cppreference.com/w/cpp/container/span).
|
||||||
|
|
||||||
|
Implementation Notes
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
### Bounds Checking ###
|
||||||
|
|
||||||
|
This implementation of `span` includes optional bounds checking, which is handled
|
||||||
|
either by throwing an exception or by calling `std::terminate()`.
|
||||||
|
|
||||||
|
The default behaviour with C++14 and later is to check the macro `NDEBUG`:
|
||||||
|
if this is set, bounds checking is disabled. Otherwise, `std::terminate()` will
|
||||||
|
be called if there is a precondition violation (i.e. the same behaviour as
|
||||||
|
`assert()`). If you wish to terminate on errors even if `NDEBUG` is set, define
|
||||||
|
the symbol `TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION` before `#include`-ing the
|
||||||
|
header.
|
||||||
|
|
||||||
|
Alternatively, if you want to throw on a contract violation, define
|
||||||
|
`TCB_SPAN_THROW_ON_CONTRACT_VIOLATION`. This will throw an exception of an
|
||||||
|
implementation-defined type (deriving from `std::logic_error`), allowing
|
||||||
|
cleanup to happen. Note that defining this symbol will cause the checks to be
|
||||||
|
run even if `NDEBUG` is set.
|
||||||
|
|
||||||
|
Lastly, if you wish to disable contract checking even in debug builds,
|
||||||
|
`#define TCB_SPAN_NO_CONTRACT_CHECKING`.
|
||||||
|
|
||||||
|
Under C++11, due to the restrictions on `constexpr` functions, contract checking
|
||||||
|
is disabled by default even if `NDEBUG` is not set. You can change this by
|
||||||
|
defining either of the above symbols, but this will result in most of `span`'s
|
||||||
|
interface becoming non-`constexpr`.
|
||||||
|
|
||||||
|
### `constexpr` ###
|
||||||
|
|
||||||
|
This implementation is fully `constexpr` under C++17 and later. Under earlier
|
||||||
|
versions, it is "as `constexpr` as possible".
|
||||||
|
|
||||||
|
Note that even in C++17, it is generally not possible to declare a `span`
|
||||||
|
as non-default constructed `constexpr` variable, for the same reason that you
|
||||||
|
cannot form a `constexpr` pointer to a value: it involves taking the address of
|
||||||
|
a compile-time variable in a way that would be visible at run-time.
|
||||||
|
You can however use a `span` freely in a `constexpr` function. For example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Okay, even in C++11
|
||||||
|
constexpr std::ptrdiff_t get_span_size(span<const int> span)
|
||||||
|
{
|
||||||
|
return span.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int arr[] = {1, 2, 3};
|
||||||
|
constexpr auto size = get_span_size(arr); // Okay
|
||||||
|
constexpr span<const int> span{arr}; // ERROR -- not a constant expression
|
||||||
|
constexpr const int* p = arr; // ERROR -- same
|
||||||
|
```
|
||||||
|
|
||||||
|
Constructor deduction guides are provided if the compiler supports them. For
|
||||||
|
older compilers, a set of `make_span()` functions are provided as an extension
|
||||||
|
which use the same logic, for example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr int c_array[] = {1, 2, 3};
|
||||||
|
std::array<int, 3> std_array{1, 2, 3};
|
||||||
|
const std::vector<int> vec{1, 2, 3};
|
||||||
|
|
||||||
|
auto s1 = make_span(c_array); // returns span<const int, 3>
|
||||||
|
auto s2 = make_span(std_array); // returns span<int, 3>
|
||||||
|
auto s3 = make_span(vec); // returns span<const int, dynamic_extent>
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatives
|
||||||
|
------------
|
||||||
|
|
||||||
|
* [Microsoft/GSL](https://github.com/Microsoft/GSL): The original `span` reference
|
||||||
|
implementation from which `std::span` was born.
|
||||||
|
|
||||||
|
* [martinmoene/span_lite](https://github.com/martinmoene/span-lite): An
|
||||||
|
alternative implementation which offers C++98 compatibility.
|
||||||
|
|
631
src/libs/3rdparty/span/span.hpp
vendored
Normal file
@@ -0,0 +1,631 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
This is an implementation of C++20's std::span
|
||||||
|
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4820.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Copyright Tristan Brindle 2018.
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file ../../LICENSE_1_0.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef TCB_SPAN_HPP_INCLUDED
|
||||||
|
#define TCB_SPAN_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#ifndef TCB_SPAN_NO_EXCEPTIONS
|
||||||
|
// Attempt to discover whether we're being compiled with exception support
|
||||||
|
#if !(defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND))
|
||||||
|
#define TCB_SPAN_NO_EXCEPTIONS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TCB_SPAN_NO_EXCEPTIONS
|
||||||
|
#include <cstdio>
|
||||||
|
#include <stdexcept>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Various feature test macros
|
||||||
|
|
||||||
|
#ifndef TCB_SPAN_NAMESPACE_NAME
|
||||||
|
#define TCB_SPAN_NAMESPACE_NAME tcb
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||||
|
#define TCB_SPAN_HAVE_CPP17
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
|
||||||
|
#define TCB_SPAN_HAVE_CPP14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace TCB_SPAN_NAMESPACE_NAME {
|
||||||
|
|
||||||
|
// Establish default contract checking behavior
|
||||||
|
#if !defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION) && \
|
||||||
|
!defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION) && \
|
||||||
|
!defined(TCB_SPAN_NO_CONTRACT_CHECKING)
|
||||||
|
#if defined(NDEBUG) || !defined(TCB_SPAN_HAVE_CPP14)
|
||||||
|
#define TCB_SPAN_NO_CONTRACT_CHECKING
|
||||||
|
#else
|
||||||
|
#define TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_THROW_ON_CONTRACT_VIOLATION)
|
||||||
|
struct contract_violation_error : std::logic_error {
|
||||||
|
explicit contract_violation_error(const char* msg) : std::logic_error(msg)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void contract_violation(const char* msg)
|
||||||
|
{
|
||||||
|
throw contract_violation_error(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION)
|
||||||
|
[[noreturn]] inline void contract_violation(const char* /*unused*/)
|
||||||
|
{
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(TCB_SPAN_NO_CONTRACT_CHECKING)
|
||||||
|
#define TCB_SPAN_STRINGIFY(cond) #cond
|
||||||
|
#define TCB_SPAN_EXPECT(cond) \
|
||||||
|
cond ? (void) 0 : contract_violation("Expected " TCB_SPAN_STRINGIFY(cond))
|
||||||
|
#else
|
||||||
|
#define TCB_SPAN_EXPECT(cond)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_inline_variables)
|
||||||
|
#define TCB_SPAN_INLINE_VAR inline
|
||||||
|
#else
|
||||||
|
#define TCB_SPAN_INLINE_VAR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_HAVE_CPP14) || \
|
||||||
|
(defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
|
||||||
|
#define TCB_SPAN_HAVE_CPP14_CONSTEXPR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR)
|
||||||
|
#define TCB_SPAN_CONSTEXPR14 constexpr
|
||||||
|
#else
|
||||||
|
#define TCB_SPAN_CONSTEXPR14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_HAVE_CPP14_CONSTEXPR) && \
|
||||||
|
(!defined(_MSC_VER) || _MSC_VER > 1900)
|
||||||
|
#define TCB_SPAN_CONSTEXPR_ASSIGN constexpr
|
||||||
|
#else
|
||||||
|
#define TCB_SPAN_CONSTEXPR_ASSIGN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_NO_CONTRACT_CHECKING)
|
||||||
|
#define TCB_SPAN_CONSTEXPR11 constexpr
|
||||||
|
#else
|
||||||
|
#define TCB_SPAN_CONSTEXPR11 TCB_SPAN_CONSTEXPR14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_deduction_guides)
|
||||||
|
#define TCB_SPAN_HAVE_DEDUCTION_GUIDES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_byte)
|
||||||
|
#define TCB_SPAN_HAVE_STD_BYTE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_array_constexpr)
|
||||||
|
#define TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_HAVE_CONSTEXPR_STD_ARRAY_ETC)
|
||||||
|
#define TCB_SPAN_ARRAY_CONSTEXPR constexpr
|
||||||
|
#else
|
||||||
|
#define TCB_SPAN_ARRAY_CONSTEXPR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TCB_SPAN_HAVE_STD_BYTE
|
||||||
|
using byte = std::byte;
|
||||||
|
#else
|
||||||
|
using byte = unsigned char;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_HAVE_CPP17)
|
||||||
|
#define TCB_SPAN_NODISCARD [[nodiscard]]
|
||||||
|
#else
|
||||||
|
#define TCB_SPAN_NODISCARD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TCB_SPAN_INLINE_VAR constexpr std::size_t dynamic_extent = SIZE_MAX;
|
||||||
|
|
||||||
|
template <typename ElementType, std::size_t Extent = dynamic_extent>
|
||||||
|
class span;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename E, std::size_t S>
|
||||||
|
struct span_storage {
|
||||||
|
constexpr span_storage() noexcept = default;
|
||||||
|
|
||||||
|
constexpr span_storage(E* p_ptr, std::size_t /*unused*/) noexcept
|
||||||
|
: ptr(p_ptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
E* ptr = nullptr;
|
||||||
|
static constexpr std::size_t size = S;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename E>
|
||||||
|
struct span_storage<E, dynamic_extent> {
|
||||||
|
constexpr span_storage() noexcept = default;
|
||||||
|
|
||||||
|
constexpr span_storage(E* p_ptr, std::size_t p_size) noexcept
|
||||||
|
: ptr(p_ptr), size(p_size)
|
||||||
|
{}
|
||||||
|
|
||||||
|
E* ptr = nullptr;
|
||||||
|
std::size_t size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reimplementation of C++17 std::size() and std::data()
|
||||||
|
#if defined(TCB_SPAN_HAVE_CPP17) || \
|
||||||
|
defined(__cpp_lib_nonmember_container_access)
|
||||||
|
using std::data;
|
||||||
|
using std::size;
|
||||||
|
#else
|
||||||
|
template <class C>
|
||||||
|
constexpr auto size(const C& c) -> decltype(c.size())
|
||||||
|
{
|
||||||
|
return c.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, std::size_t N>
|
||||||
|
constexpr std::size_t size(const T (&)[N]) noexcept
|
||||||
|
{
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class C>
|
||||||
|
constexpr auto data(C& c) -> decltype(c.data())
|
||||||
|
{
|
||||||
|
return c.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class C>
|
||||||
|
constexpr auto data(const C& c) -> decltype(c.data())
|
||||||
|
{
|
||||||
|
return c.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, std::size_t N>
|
||||||
|
constexpr T* data(T (&array)[N]) noexcept
|
||||||
|
{
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class E>
|
||||||
|
constexpr const E* data(std::initializer_list<E> il) noexcept
|
||||||
|
{
|
||||||
|
return il.begin();
|
||||||
|
}
|
||||||
|
#endif // TCB_SPAN_HAVE_CPP17
|
||||||
|
|
||||||
|
#if defined(TCB_SPAN_HAVE_CPP17) || defined(__cpp_lib_void_t)
|
||||||
|
using std::void_t;
|
||||||
|
#else
|
||||||
|
template <typename...>
|
||||||
|
using void_t = void;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using uncvref_t =
|
||||||
|
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||||
|
|
||||||
|
template <typename>
|
||||||
|
struct is_span : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T, std::size_t S>
|
||||||
|
struct is_span<span<T, S>> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename>
|
||||||
|
struct is_std_array : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
struct is_std_array<std::array<T, N>> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename, typename = void>
|
||||||
|
struct has_size_and_data : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct has_size_and_data<T, void_t<decltype(detail::size(std::declval<T>())),
|
||||||
|
decltype(detail::data(std::declval<T>()))>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
template <typename C, typename U = uncvref_t<C>>
|
||||||
|
struct is_container {
|
||||||
|
static constexpr bool value =
|
||||||
|
!is_span<U>::value && !is_std_array<U>::value &&
|
||||||
|
!std::is_array<U>::value && has_size_and_data<C>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using remove_pointer_t = typename std::remove_pointer<T>::type;
|
||||||
|
|
||||||
|
template <typename, typename, typename = void>
|
||||||
|
struct is_container_element_type_compatible : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T, typename E>
|
||||||
|
struct is_container_element_type_compatible<
|
||||||
|
T, E,
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_same<typename std::remove_cv<decltype(
|
||||||
|
detail::data(std::declval<T>()))>::type,
|
||||||
|
void>::value>::type>
|
||||||
|
: std::is_convertible<
|
||||||
|
remove_pointer_t<decltype(detail::data(std::declval<T>()))> (*)[],
|
||||||
|
E (*)[]> {};
|
||||||
|
|
||||||
|
template <typename, typename = size_t>
|
||||||
|
struct is_complete : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_complete<T, decltype(sizeof(T))> : std::true_type {};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename ElementType, std::size_t Extent>
|
||||||
|
class span {
|
||||||
|
static_assert(std::is_object<ElementType>::value,
|
||||||
|
"A span's ElementType must be an object type (not a "
|
||||||
|
"reference type or void)");
|
||||||
|
static_assert(detail::is_complete<ElementType>::value,
|
||||||
|
"A span's ElementType must be a complete type (not a forward "
|
||||||
|
"declaration)");
|
||||||
|
static_assert(!std::is_abstract<ElementType>::value,
|
||||||
|
"A span's ElementType cannot be an abstract class type");
|
||||||
|
|
||||||
|
using storage_type = detail::span_storage<ElementType, Extent>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// constants and types
|
||||||
|
using element_type = ElementType;
|
||||||
|
using value_type = typename std::remove_cv<ElementType>::type;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = element_type*;
|
||||||
|
using const_pointer = const element_type*;
|
||||||
|
using reference = element_type&;
|
||||||
|
using iterator = pointer;
|
||||||
|
using const_iterator = const_pointer;
|
||||||
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||||
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
|
||||||
|
static constexpr size_type extent = Extent;
|
||||||
|
|
||||||
|
// [span.cons], span constructors, copy, assignment, and destructor
|
||||||
|
template <
|
||||||
|
std::size_t E = Extent,
|
||||||
|
typename std::enable_if<(E == dynamic_extent || E <= 0), int>::type = 0>
|
||||||
|
constexpr span() noexcept
|
||||||
|
{}
|
||||||
|
|
||||||
|
TCB_SPAN_CONSTEXPR11 span(pointer ptr, size_type count)
|
||||||
|
: storage_(ptr, count)
|
||||||
|
{
|
||||||
|
TCB_SPAN_EXPECT(extent == dynamic_extent || count == extent);
|
||||||
|
}
|
||||||
|
|
||||||
|
TCB_SPAN_CONSTEXPR11 span(pointer first_elem, pointer last_elem)
|
||||||
|
: storage_(first_elem, last_elem - first_elem)
|
||||||
|
{
|
||||||
|
TCB_SPAN_EXPECT(extent == dynamic_extent ||
|
||||||
|
last_elem - first_elem ==
|
||||||
|
static_cast<std::ptrdiff_t>(extent));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t N, std::size_t E = Extent,
|
||||||
|
typename std::enable_if<
|
||||||
|
(E == dynamic_extent || N == E) &&
|
||||||
|
detail::is_container_element_type_compatible<
|
||||||
|
element_type (&)[N], ElementType>::value,
|
||||||
|
int>::type = 0>
|
||||||
|
constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <std::size_t N, std::size_t E = Extent,
|
||||||
|
typename std::enable_if<
|
||||||
|
(E == dynamic_extent || N == E) &&
|
||||||
|
detail::is_container_element_type_compatible<
|
||||||
|
std::array<value_type, N>&, ElementType>::value,
|
||||||
|
int>::type = 0>
|
||||||
|
TCB_SPAN_ARRAY_CONSTEXPR span(std::array<value_type, N>& arr) noexcept
|
||||||
|
: storage_(arr.data(), N)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <std::size_t N, std::size_t E = Extent,
|
||||||
|
typename std::enable_if<
|
||||||
|
(E == dynamic_extent || N == E) &&
|
||||||
|
detail::is_container_element_type_compatible<
|
||||||
|
const std::array<value_type, N>&, ElementType>::value,
|
||||||
|
int>::type = 0>
|
||||||
|
TCB_SPAN_ARRAY_CONSTEXPR span(const std::array<value_type, N>& arr) noexcept
|
||||||
|
: storage_(arr.data(), N)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Container, std::size_t E = Extent,
|
||||||
|
typename std::enable_if<
|
||||||
|
E == dynamic_extent && detail::is_container<Container>::value &&
|
||||||
|
detail::is_container_element_type_compatible<
|
||||||
|
Container&, ElementType>::value,
|
||||||
|
int>::type = 0>
|
||||||
|
constexpr span(Container& cont)
|
||||||
|
: storage_(detail::data(cont), detail::size(cont))
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Container, std::size_t E = Extent,
|
||||||
|
typename std::enable_if<
|
||||||
|
E == dynamic_extent && detail::is_container<Container>::value &&
|
||||||
|
detail::is_container_element_type_compatible<
|
||||||
|
const Container&, ElementType>::value,
|
||||||
|
int>::type = 0>
|
||||||
|
constexpr span(const Container& cont)
|
||||||
|
: storage_(detail::data(cont), detail::size(cont))
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr span(const span& other) noexcept = default;
|
||||||
|
|
||||||
|
template <typename OtherElementType, std::size_t OtherExtent,
|
||||||
|
typename std::enable_if<
|
||||||
|
(Extent == OtherExtent || Extent == dynamic_extent) &&
|
||||||
|
std::is_convertible<OtherElementType (*)[],
|
||||||
|
ElementType (*)[]>::value,
|
||||||
|
int>::type = 0>
|
||||||
|
constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
|
||||||
|
: storage_(other.data(), other.size())
|
||||||
|
{}
|
||||||
|
|
||||||
|
~span() noexcept = default;
|
||||||
|
|
||||||
|
TCB_SPAN_CONSTEXPR_ASSIGN span&
|
||||||
|
operator=(const span& other) noexcept = default;
|
||||||
|
|
||||||
|
// [span.sub], span subviews
|
||||||
|
template <std::size_t Count>
|
||||||
|
TCB_SPAN_CONSTEXPR11 span<element_type, Count> first() const
|
||||||
|
{
|
||||||
|
TCB_SPAN_EXPECT(Count <= size());
|
||||||
|
return {data(), Count};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t Count>
|
||||||
|
TCB_SPAN_CONSTEXPR11 span<element_type, Count> last() const
|
||||||
|
{
|
||||||
|
TCB_SPAN_EXPECT(Count <= size());
|
||||||
|
return {data() + (size() - Count), Count};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t Offset, std::size_t Count = dynamic_extent>
|
||||||
|
using subspan_return_t =
|
||||||
|
span<ElementType, Count != dynamic_extent
|
||||||
|
? Count
|
||||||
|
: (Extent != dynamic_extent ? Extent - Offset
|
||||||
|
: dynamic_extent)>;
|
||||||
|
|
||||||
|
template <std::size_t Offset, std::size_t Count = dynamic_extent>
|
||||||
|
TCB_SPAN_CONSTEXPR11 subspan_return_t<Offset, Count> subspan() const
|
||||||
|
{
|
||||||
|
TCB_SPAN_EXPECT(Offset <= size() &&
|
||||||
|
(Count == dynamic_extent || Offset + Count <= size()));
|
||||||
|
return {data() + Offset,
|
||||||
|
Count != dynamic_extent ? Count : size() - Offset};
|
||||||
|
}
|
||||||
|
|
||||||
|
TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent>
|
||||||
|
first(size_type count) const
|
||||||
|
{
|
||||||
|
TCB_SPAN_EXPECT(count <= size());
|
||||||
|
return {data(), count};
|
||||||
|
}
|
||||||
|
|
||||||
|
TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent>
|
||||||
|
last(size_type count) const
|
||||||
|
{
|
||||||
|
TCB_SPAN_EXPECT(count <= size());
|
||||||
|
return {data() + (size() - count), count};
|
||||||
|
}
|
||||||
|
|
||||||
|
TCB_SPAN_CONSTEXPR11 span<element_type, dynamic_extent>
|
||||||
|
subspan(size_type offset, size_type count = dynamic_extent) const
|
||||||
|
{
|
||||||
|
TCB_SPAN_EXPECT(offset <= size() &&
|
||||||
|
(count == dynamic_extent || offset + count <= size()));
|
||||||
|
return {data() + offset,
|
||||||
|
count == dynamic_extent ? size() - offset : count};
|
||||||
|
}
|
||||||
|
|
||||||
|
// [span.obs], span observers
|
||||||
|
constexpr size_type size() const noexcept { return storage_.size; }
|
||||||
|
|
||||||
|
constexpr size_type size_bytes() const noexcept
|
||||||
|
{
|
||||||
|
return size() * sizeof(element_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
TCB_SPAN_NODISCARD constexpr bool empty() const noexcept
|
||||||
|
{
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [span.elem], span element access
|
||||||
|
TCB_SPAN_CONSTEXPR11 reference operator[](size_type idx) const
|
||||||
|
{
|
||||||
|
TCB_SPAN_EXPECT(idx < size());
|
||||||
|
return *(data() + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TCB_SPAN_CONSTEXPR11 reference front() const
|
||||||
|
{
|
||||||
|
TCB_SPAN_EXPECT(!empty());
|
||||||
|
return *data();
|
||||||
|
}
|
||||||
|
|
||||||
|
TCB_SPAN_CONSTEXPR11 reference back() const
|
||||||
|
{
|
||||||
|
TCB_SPAN_EXPECT(!empty());
|
||||||
|
return *(data() + (size() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr pointer data() const noexcept { return storage_.ptr; }
|
||||||
|
|
||||||
|
// [span.iterators], span iterator support
|
||||||
|
constexpr iterator begin() const noexcept { return data(); }
|
||||||
|
|
||||||
|
constexpr iterator end() const noexcept { return data() + size(); }
|
||||||
|
|
||||||
|
constexpr const_iterator cbegin() const noexcept { return begin(); }
|
||||||
|
|
||||||
|
constexpr const_iterator cend() const noexcept { return end(); }
|
||||||
|
|
||||||
|
TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rbegin() const noexcept
|
||||||
|
{
|
||||||
|
return reverse_iterator(end());
|
||||||
|
}
|
||||||
|
|
||||||
|
TCB_SPAN_ARRAY_CONSTEXPR reverse_iterator rend() const noexcept
|
||||||
|
{
|
||||||
|
return reverse_iterator(begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
TCB_SPAN_ARRAY_CONSTEXPR const_reverse_iterator crbegin() const noexcept
|
||||||
|
{
|
||||||
|
return const_reverse_iterator(cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
TCB_SPAN_ARRAY_CONSTEXPR const_reverse_iterator crend() const noexcept
|
||||||
|
{
|
||||||
|
return const_reverse_iterator(cbegin());
|
||||||
|
}
|
||||||
|
|
||||||
|
friend constexpr iterator begin(span s) noexcept { return s.begin(); }
|
||||||
|
|
||||||
|
friend constexpr iterator end(span s) noexcept { return s.end(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
storage_type storage_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef TCB_SPAN_HAVE_DEDUCTION_GUIDES
|
||||||
|
|
||||||
|
/* Deduction Guides */
|
||||||
|
template <class T, size_t N>
|
||||||
|
span(T (&)[N])->span<T, N>;
|
||||||
|
|
||||||
|
template <class T, size_t N>
|
||||||
|
span(std::array<T, N>&)->span<T, N>;
|
||||||
|
|
||||||
|
template <class T, size_t N>
|
||||||
|
span(const std::array<T, N>&)->span<const T, N>;
|
||||||
|
|
||||||
|
template <class Container>
|
||||||
|
span(Container&)->span<typename Container::value_type>;
|
||||||
|
|
||||||
|
template <class Container>
|
||||||
|
span(const Container&)->span<const typename Container::value_type>;
|
||||||
|
|
||||||
|
#endif // TCB_HAVE_DEDUCTION_GUIDES
|
||||||
|
|
||||||
|
template <typename ElementType, std::size_t Extent>
|
||||||
|
constexpr span<ElementType, Extent>
|
||||||
|
make_span(span<ElementType, Extent> s) noexcept
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
constexpr span<T, N> make_span(T (&arr)[N]) noexcept
|
||||||
|
{
|
||||||
|
return {arr};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
TCB_SPAN_ARRAY_CONSTEXPR span<T, N> make_span(std::array<T, N>& arr) noexcept
|
||||||
|
{
|
||||||
|
return {arr};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
TCB_SPAN_ARRAY_CONSTEXPR span<const T, N>
|
||||||
|
make_span(const std::array<T, N>& arr) noexcept
|
||||||
|
{
|
||||||
|
return {arr};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
constexpr span<typename Container::value_type> make_span(Container& cont)
|
||||||
|
{
|
||||||
|
return {cont};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
constexpr span<const typename Container::value_type>
|
||||||
|
make_span(const Container& cont)
|
||||||
|
{
|
||||||
|
return {cont};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ElementType, std::size_t Extent>
|
||||||
|
span<const byte, ((Extent == dynamic_extent) ? dynamic_extent
|
||||||
|
: sizeof(ElementType) * Extent)>
|
||||||
|
as_bytes(span<ElementType, Extent> s) noexcept
|
||||||
|
{
|
||||||
|
return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
class ElementType, size_t Extent,
|
||||||
|
typename std::enable_if<!std::is_const<ElementType>::value, int>::type = 0>
|
||||||
|
span<byte, ((Extent == dynamic_extent) ? dynamic_extent
|
||||||
|
: sizeof(ElementType) * Extent)>
|
||||||
|
as_writable_bytes(span<ElementType, Extent> s) noexcept
|
||||||
|
{
|
||||||
|
return {reinterpret_cast<byte*>(s.data()), s.size_bytes()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t N, typename E, std::size_t S>
|
||||||
|
constexpr auto get(span<E, S> s) -> decltype(s[N])
|
||||||
|
{
|
||||||
|
return s[N];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace TCB_SPAN_NAMESPACE_NAME
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template <typename ElementType, size_t Extent>
|
||||||
|
class tuple_size<TCB_SPAN_NAMESPACE_NAME::span<ElementType, Extent>>
|
||||||
|
: public integral_constant<size_t, Extent> {};
|
||||||
|
|
||||||
|
template <typename ElementType>
|
||||||
|
class tuple_size<TCB_SPAN_NAMESPACE_NAME::span<
|
||||||
|
ElementType, TCB_SPAN_NAMESPACE_NAME::dynamic_extent>>; // not defined
|
||||||
|
|
||||||
|
template <size_t I, typename ElementType, size_t Extent>
|
||||||
|
class tuple_element<I, TCB_SPAN_NAMESPACE_NAME::span<ElementType, Extent>> {
|
||||||
|
public:
|
||||||
|
static_assert(Extent != TCB_SPAN_NAMESPACE_NAME::dynamic_extent &&
|
||||||
|
I < Extent,
|
||||||
|
"");
|
||||||
|
using type = ElementType;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace std
|
||||||
|
|
||||||
|
#endif // TCB_SPAN_HPP_INCLUDED
|
403
src/libs/3rdparty/sqlite/carray.c
vendored
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
/*
|
||||||
|
** 2016-06-29
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
**
|
||||||
|
** This file demonstrates how to create a table-valued-function that
|
||||||
|
** returns the values in a C-language array.
|
||||||
|
** Examples:
|
||||||
|
**
|
||||||
|
** SELECT * FROM carray($ptr,5)
|
||||||
|
**
|
||||||
|
** The query above returns 5 integers contained in a C-language array
|
||||||
|
** at the address $ptr. $ptr is a pointer to the array of integers.
|
||||||
|
** The pointer value must be assigned to $ptr using the
|
||||||
|
** sqlite3_bind_pointer() interface with a pointer type of "carray".
|
||||||
|
** For example:
|
||||||
|
**
|
||||||
|
** static int aX[] = { 53, 9, 17, 2231, 4, 99 };
|
||||||
|
** int i = sqlite3_bind_parameter_index(pStmt, "$ptr");
|
||||||
|
** sqlite3_bind_pointer(pStmt, i, aX, "carray", 0);
|
||||||
|
**
|
||||||
|
** There is an optional third parameter to determine the datatype of
|
||||||
|
** the C-language array. Allowed values of the third parameter are
|
||||||
|
** 'int32', 'int64', 'double', 'char*'. Example:
|
||||||
|
**
|
||||||
|
** SELECT * FROM carray($ptr,10,'char*');
|
||||||
|
**
|
||||||
|
** The default value of the third parameter is 'int32'.
|
||||||
|
**
|
||||||
|
** HOW IT WORKS
|
||||||
|
**
|
||||||
|
** The carray "function" is really a virtual table with the
|
||||||
|
** following schema:
|
||||||
|
**
|
||||||
|
** CREATE TABLE carray(
|
||||||
|
** value,
|
||||||
|
** pointer HIDDEN,
|
||||||
|
** count HIDDEN,
|
||||||
|
** ctype TEXT HIDDEN
|
||||||
|
** );
|
||||||
|
**
|
||||||
|
** If the hidden columns "pointer" and "count" are unconstrained, then
|
||||||
|
** the virtual table has no rows. Otherwise, the virtual table interprets
|
||||||
|
** the integer value of "pointer" as a pointer to the array and "count"
|
||||||
|
** as the number of elements in the array. The virtual table steps through
|
||||||
|
** the array, element by element.
|
||||||
|
*/
|
||||||
|
#include "sqlite3ext.h"
|
||||||
|
SQLITE_EXTENSION_INIT1
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Allowed datatypes
|
||||||
|
*/
|
||||||
|
#define CARRAY_INT32 0
|
||||||
|
#define CARRAY_INT64 1
|
||||||
|
#define CARRAY_DOUBLE 2
|
||||||
|
#define CARRAY_TEXT 3
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Names of types
|
||||||
|
*/
|
||||||
|
static const char *azType[] = { "int32", "int64", "double", "char*" };
|
||||||
|
|
||||||
|
|
||||||
|
/* carray_cursor is a subclass of sqlite3_vtab_cursor which will
|
||||||
|
** serve as the underlying representation of a cursor that scans
|
||||||
|
** over rows of the result
|
||||||
|
*/
|
||||||
|
typedef struct carray_cursor carray_cursor;
|
||||||
|
struct carray_cursor {
|
||||||
|
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||||
|
sqlite3_int64 iRowid; /* The rowid */
|
||||||
|
void *pPtr; /* Pointer to the array of values */
|
||||||
|
sqlite3_int64 iCnt; /* Number of integers in the array */
|
||||||
|
unsigned char eType; /* One of the CARRAY_type values */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The carrayConnect() method is invoked to create a new
|
||||||
|
** carray_vtab that describes the carray virtual table.
|
||||||
|
**
|
||||||
|
** Think of this routine as the constructor for carray_vtab objects.
|
||||||
|
**
|
||||||
|
** All this routine needs to do is:
|
||||||
|
**
|
||||||
|
** (1) Allocate the carray_vtab object and initialize all fields.
|
||||||
|
**
|
||||||
|
** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
|
||||||
|
** result set of queries against carray will look like.
|
||||||
|
*/
|
||||||
|
static int carrayConnect(
|
||||||
|
sqlite3 *db,
|
||||||
|
void *pAux,
|
||||||
|
int argc, const char *const*argv,
|
||||||
|
sqlite3_vtab **ppVtab,
|
||||||
|
char **pzErr
|
||||||
|
){
|
||||||
|
sqlite3_vtab *pNew;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Column numbers */
|
||||||
|
#define CARRAY_COLUMN_VALUE 0
|
||||||
|
#define CARRAY_COLUMN_POINTER 1
|
||||||
|
#define CARRAY_COLUMN_COUNT 2
|
||||||
|
#define CARRAY_COLUMN_CTYPE 3
|
||||||
|
|
||||||
|
rc = sqlite3_declare_vtab(db,
|
||||||
|
"CREATE TABLE x(value,pointer hidden,count hidden,ctype hidden)");
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||||
|
if( pNew==0 ) return SQLITE_NOMEM;
|
||||||
|
memset(pNew, 0, sizeof(*pNew));
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This method is the destructor for carray_cursor objects.
|
||||||
|
*/
|
||||||
|
static int carrayDisconnect(sqlite3_vtab *pVtab){
|
||||||
|
sqlite3_free(pVtab);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Constructor for a new carray_cursor object.
|
||||||
|
*/
|
||||||
|
static int carrayOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor)
|
||||||
|
{
|
||||||
|
carray_cursor *pCur;
|
||||||
|
|
||||||
|
pCur = sqlite3_malloc(sizeof(*pCur));
|
||||||
|
if (pCur == 0)
|
||||||
|
return SQLITE_NOMEM;
|
||||||
|
memset(pCur, 0, sizeof(*pCur));
|
||||||
|
*ppCursor = &pCur->base;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Destructor for a carray_cursor.
|
||||||
|
*/
|
||||||
|
static int carrayClose(sqlite3_vtab_cursor *cur){
|
||||||
|
sqlite3_free(cur);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Advance a carray_cursor to its next row of output.
|
||||||
|
*/
|
||||||
|
static int carrayNext(sqlite3_vtab_cursor *cur){
|
||||||
|
carray_cursor *pCur = (carray_cursor*)cur;
|
||||||
|
pCur->iRowid++;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return values of columns for the row at which the carray_cursor
|
||||||
|
** is currently pointing.
|
||||||
|
*/
|
||||||
|
static int carrayColumn(
|
||||||
|
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||||
|
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||||
|
int i /* Which column to return */
|
||||||
|
){
|
||||||
|
carray_cursor *pCur = (carray_cursor*)cur;
|
||||||
|
sqlite3_int64 x = 0;
|
||||||
|
switch( i ){
|
||||||
|
case CARRAY_COLUMN_POINTER: return SQLITE_OK;
|
||||||
|
case CARRAY_COLUMN_COUNT: x = pCur->iCnt; break;
|
||||||
|
case CARRAY_COLUMN_CTYPE: {
|
||||||
|
sqlite3_result_text(ctx, azType[pCur->eType], -1, SQLITE_STATIC);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
switch( pCur->eType ){
|
||||||
|
case CARRAY_INT32: {
|
||||||
|
int *p = (int*)pCur->pPtr;
|
||||||
|
sqlite3_result_int(ctx, p[pCur->iRowid-1]);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
case CARRAY_INT64: {
|
||||||
|
sqlite3_int64 *p = (sqlite3_int64*)pCur->pPtr;
|
||||||
|
sqlite3_result_int64(ctx, p[pCur->iRowid-1]);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
case CARRAY_DOUBLE: {
|
||||||
|
double *p = (double*)pCur->pPtr;
|
||||||
|
sqlite3_result_double(ctx, p[pCur->iRowid-1]);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
case CARRAY_TEXT: {
|
||||||
|
const char **p = (const char**)pCur->pPtr;
|
||||||
|
sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlite3_result_int64(ctx, x);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return the rowid for the current row. In this implementation, the
|
||||||
|
** rowid is the same as the output value.
|
||||||
|
*/
|
||||||
|
static int carrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||||
|
carray_cursor *pCur = (carray_cursor*)cur;
|
||||||
|
*pRowid = pCur->iRowid;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return TRUE if the cursor has been moved off of the last
|
||||||
|
** row of output.
|
||||||
|
*/
|
||||||
|
static int carrayEof(sqlite3_vtab_cursor *cur){
|
||||||
|
carray_cursor *pCur = (carray_cursor*)cur;
|
||||||
|
return pCur->iRowid>pCur->iCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This method is called to "rewind" the carray_cursor object back
|
||||||
|
** to the first row of output.
|
||||||
|
*/
|
||||||
|
static int carrayFilter(
|
||||||
|
sqlite3_vtab_cursor *pVtabCursor,
|
||||||
|
int idxNum, const char *idxStr,
|
||||||
|
int argc, sqlite3_value **argv
|
||||||
|
){
|
||||||
|
carray_cursor *pCur = (carray_cursor *)pVtabCursor;
|
||||||
|
if( idxNum ){
|
||||||
|
pCur->pPtr = sqlite3_value_pointer(argv[0], "carray");
|
||||||
|
pCur->iCnt = pCur->pPtr ? sqlite3_value_int64(argv[1]) : 0;
|
||||||
|
if( idxNum<3 ){
|
||||||
|
pCur->eType = CARRAY_INT32;
|
||||||
|
}else{
|
||||||
|
unsigned char i;
|
||||||
|
const char *zType = (const char*)sqlite3_value_text(argv[2]);
|
||||||
|
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
|
||||||
|
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
|
||||||
|
}
|
||||||
|
if( i>=sizeof(azType)/sizeof(azType[0]) ){
|
||||||
|
pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf(
|
||||||
|
"unknown datatype: %Q", zType);
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}else{
|
||||||
|
pCur->eType = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
pCur->pPtr = 0;
|
||||||
|
pCur->iCnt = 0;
|
||||||
|
}
|
||||||
|
pCur->iRowid = 1;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** SQLite will invoke this method one or more times while planning a query
|
||||||
|
** that uses the carray virtual table. This routine needs to create
|
||||||
|
** a query plan for each invocation and compute an estimated cost for that
|
||||||
|
** plan.
|
||||||
|
**
|
||||||
|
** In this implementation idxNum is used to represent the
|
||||||
|
** query plan. idxStr is unused.
|
||||||
|
**
|
||||||
|
** idxNum is 2 if the pointer= and count= constraints exist,
|
||||||
|
** 3 if the ctype= constraint also exists, and is 0 otherwise.
|
||||||
|
** If idxNum is 0, then carray becomes an empty table.
|
||||||
|
*/
|
||||||
|
static int carrayBestIndex(
|
||||||
|
sqlite3_vtab *tab,
|
||||||
|
sqlite3_index_info *pIdxInfo
|
||||||
|
){
|
||||||
|
int i; /* Loop over constraints */
|
||||||
|
int ptrIdx = -1; /* Index of the pointer= constraint, or -1 if none */
|
||||||
|
int cntIdx = -1; /* Index of the count= constraint, or -1 if none */
|
||||||
|
int ctypeIdx = -1; /* Index of the ctype= constraint, or -1 if none */
|
||||||
|
|
||||||
|
const struct sqlite3_index_constraint *pConstraint;
|
||||||
|
pConstraint = pIdxInfo->aConstraint;
|
||||||
|
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||||
|
if( pConstraint->usable==0 ) continue;
|
||||||
|
if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||||
|
switch( pConstraint->iColumn ){
|
||||||
|
case CARRAY_COLUMN_POINTER:
|
||||||
|
ptrIdx = i;
|
||||||
|
break;
|
||||||
|
case CARRAY_COLUMN_COUNT:
|
||||||
|
cntIdx = i;
|
||||||
|
break;
|
||||||
|
case CARRAY_COLUMN_CTYPE:
|
||||||
|
ctypeIdx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( ptrIdx>=0 && cntIdx>=0 ){
|
||||||
|
pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1;
|
||||||
|
pIdxInfo->aConstraintUsage[ptrIdx].omit = 1;
|
||||||
|
pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2;
|
||||||
|
pIdxInfo->aConstraintUsage[cntIdx].omit = 1;
|
||||||
|
pIdxInfo->estimatedCost = (double)1;
|
||||||
|
pIdxInfo->estimatedRows = 100;
|
||||||
|
pIdxInfo->idxNum = 2;
|
||||||
|
if( ctypeIdx>=0 ){
|
||||||
|
pIdxInfo->aConstraintUsage[ctypeIdx].argvIndex = 3;
|
||||||
|
pIdxInfo->aConstraintUsage[ctypeIdx].omit = 1;
|
||||||
|
pIdxInfo->idxNum = 3;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
pIdxInfo->estimatedCost = (double)2147483647;
|
||||||
|
pIdxInfo->estimatedRows = 2147483647;
|
||||||
|
pIdxInfo->idxNum = 0;
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This following structure defines all the methods for the
|
||||||
|
** carray virtual table.
|
||||||
|
*/
|
||||||
|
static sqlite3_module carrayModule = {
|
||||||
|
0, /* iVersion */
|
||||||
|
0, /* xCreate */
|
||||||
|
carrayConnect, /* xConnect */
|
||||||
|
carrayBestIndex, /* xBestIndex */
|
||||||
|
carrayDisconnect, /* xDisconnect */
|
||||||
|
0, /* xDestroy */
|
||||||
|
carrayOpen, /* xOpen - open a cursor */
|
||||||
|
carrayClose, /* xClose - close a cursor */
|
||||||
|
carrayFilter, /* xFilter - configure scan constraints */
|
||||||
|
carrayNext, /* xNext - advance a cursor */
|
||||||
|
carrayEof, /* xEof - check for end of scan */
|
||||||
|
carrayColumn, /* xColumn - read data */
|
||||||
|
carrayRowid, /* xRowid - read data */
|
||||||
|
0, /* xUpdate */
|
||||||
|
0, /* xBegin */
|
||||||
|
0, /* xSync */
|
||||||
|
0, /* xCommit */
|
||||||
|
0, /* xRollback */
|
||||||
|
0, /* xFindMethod */
|
||||||
|
0, /* xRename */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** For testing purpose in the TCL test harness, we need a method for
|
||||||
|
** setting the pointer value. The inttoptr(X) SQL function accomplishes
|
||||||
|
** this. Tcl script will bind an integer to X and the inttoptr() SQL
|
||||||
|
** function will use sqlite3_result_pointer() to convert that integer into
|
||||||
|
** a pointer.
|
||||||
|
**
|
||||||
|
** This is for testing on TCL only.
|
||||||
|
*/
|
||||||
|
#ifdef SQLITE_TEST
|
||||||
|
static void inttoptrFunc(
|
||||||
|
sqlite3_context *context,
|
||||||
|
int argc,
|
||||||
|
sqlite3_value **argv
|
||||||
|
){
|
||||||
|
void *p;
|
||||||
|
sqlite3_int64 i64;
|
||||||
|
i64 = sqlite3_value_int64(argv[0]);
|
||||||
|
if( sizeof(i64)==sizeof(p) ){
|
||||||
|
memcpy(&p, &i64, sizeof(p));
|
||||||
|
}else{
|
||||||
|
int i32 = i64 & 0xffffffff;
|
||||||
|
memcpy(&p, &i32, sizeof(p));
|
||||||
|
}
|
||||||
|
sqlite3_result_pointer(context, p, "carray", 0);
|
||||||
|
}
|
||||||
|
#endif /* SQLITE_TEST */
|
||||||
|
|
||||||
|
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||||
|
|
||||||
|
int sqlite3_carray_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi)
|
||||||
|
{
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
SQLITE_EXTENSION_INIT2(pApi);
|
||||||
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
|
rc = sqlite3_create_module(db, "carray", &carrayModule, 0);
|
||||||
|
|
||||||
|
#ifdef SQLITE_TEST
|
||||||
|
if (rc == SQLITE_OK) {
|
||||||
|
rc = sqlite3_create_function(db, "inttoptr", 1, SQLITE_UTF8, 0, inttoptrFunc, 0, 0);
|
||||||
|
}
|
||||||
|
#endif /* SQLITE_TEST */
|
||||||
|
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||||
|
return rc;
|
||||||
|
}
|
231
src/libs/3rdparty/sqlite/okapi_bm25.h
vendored
@@ -1,231 +0,0 @@
|
|||||||
#include <math.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "sqlite3.h"
|
|
||||||
|
|
||||||
|
|
||||||
static void okapi_bm25(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal) {
|
|
||||||
assert(sizeof(int) == 4);
|
|
||||||
|
|
||||||
const unsigned int *matchinfo = (const unsigned int *)sqlite3_value_blob(apVal[0]);
|
|
||||||
int searchTextCol = sqlite3_value_int(apVal[1]);
|
|
||||||
|
|
||||||
double K1 = ((nVal >= 3) ? sqlite3_value_double(apVal[2]) : 1.2);
|
|
||||||
double B = ((nVal >= 4) ? sqlite3_value_double(apVal[3]) : 0.75);
|
|
||||||
|
|
||||||
int P_OFFSET = 0;
|
|
||||||
int C_OFFSET = 1;
|
|
||||||
int X_OFFSET = 2;
|
|
||||||
|
|
||||||
int termCount = matchinfo[P_OFFSET];
|
|
||||||
int colCount = matchinfo[C_OFFSET];
|
|
||||||
|
|
||||||
int N_OFFSET = X_OFFSET + 3*termCount*colCount;
|
|
||||||
int A_OFFSET = N_OFFSET + 1;
|
|
||||||
int L_OFFSET = (A_OFFSET + colCount);
|
|
||||||
|
|
||||||
|
|
||||||
double totalDocs = matchinfo[N_OFFSET];
|
|
||||||
double avgLength = matchinfo[A_OFFSET + searchTextCol];
|
|
||||||
double docLength = matchinfo[L_OFFSET + searchTextCol];
|
|
||||||
|
|
||||||
double sum = 0.0;
|
|
||||||
|
|
||||||
for (int i = 0; i < termCount; i++) {
|
|
||||||
int currentX = X_OFFSET + (3 * searchTextCol * (i + 1));
|
|
||||||
double termFrequency = matchinfo[currentX];
|
|
||||||
double docsWithTerm = matchinfo[currentX + 2];
|
|
||||||
|
|
||||||
double idf = log(
|
|
||||||
(totalDocs - docsWithTerm + 0.5) /
|
|
||||||
(docsWithTerm + 0.5)
|
|
||||||
);
|
|
||||||
|
|
||||||
double rightSide = (
|
|
||||||
(termFrequency * (K1 + 1)) /
|
|
||||||
(termFrequency + (K1 * (1 - B + (B * (docLength / avgLength)))))
|
|
||||||
);
|
|
||||||
|
|
||||||
sum += (idf * rightSide);
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3_result_double(pCtx, sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Created by Joshua Wilson on 27/05/14.
|
|
||||||
// Copyright (c) 2014 Joshua Wilson. All rights reserved.
|
|
||||||
// https://github.com/neozenith/sqlite-okapi-bm25
|
|
||||||
//
|
|
||||||
// This is an extension to the work of "Radford 'rads' Smith"
|
|
||||||
// found at: https://github.com/rads/sqlite-okapi-bm25
|
|
||||||
// which is covered by the MIT License
|
|
||||||
// http://opensource.org/licenses/MIT
|
|
||||||
// the following code shall also be covered by the same MIT License
|
|
||||||
|
|
||||||
static void okapi_bm25f(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal) {
|
|
||||||
assert(sizeof(int) == 4);
|
|
||||||
|
|
||||||
const unsigned int *matchinfo = (const unsigned int *)sqlite3_value_blob(apVal[0]);
|
|
||||||
|
|
||||||
|
|
||||||
//Setting the default values and ignoring argument based inputs so the extra
|
|
||||||
//arguments can be the column weights instead.
|
|
||||||
double K1 = 1.2;// ((nVal >= 3) ? sqlite3_value_double(apVal[2]) : 1.2);
|
|
||||||
double B = 0.75;// ((nVal >= 4) ? sqlite3_value_double(apVal[3]) : 0.75);
|
|
||||||
|
|
||||||
//For a good explanation fo the maths and how to choose these variables
|
|
||||||
//http://stackoverflow.com/a/23161886/622276
|
|
||||||
|
|
||||||
//NOTE: the rearranged order of parameters to match the order presented on
|
|
||||||
//SQLite3 FTS3 documentation 'pcxnals' (http://www.sqlite.org/fts3.html#matchinfo)
|
|
||||||
|
|
||||||
int P_OFFSET = 0;
|
|
||||||
int C_OFFSET = 1;
|
|
||||||
int X_OFFSET = 2;
|
|
||||||
|
|
||||||
int termCount = matchinfo[P_OFFSET];
|
|
||||||
int colCount = matchinfo[C_OFFSET];
|
|
||||||
|
|
||||||
int N_OFFSET = X_OFFSET + 3*termCount*colCount;
|
|
||||||
int A_OFFSET = N_OFFSET + 1;
|
|
||||||
int L_OFFSET = (A_OFFSET + colCount);
|
|
||||||
// int S_OFFSET = (L_OFFSET + colCount); //useful as a pseudo proximity weighting per field/column
|
|
||||||
|
|
||||||
double totalDocs = matchinfo[N_OFFSET];
|
|
||||||
|
|
||||||
double avgLength = 0.0;
|
|
||||||
double docLength = 0.0;
|
|
||||||
|
|
||||||
for (int col = 0; col < colCount; col++)
|
|
||||||
{
|
|
||||||
avgLength += matchinfo[A_OFFSET + col];
|
|
||||||
docLength += matchinfo[L_OFFSET + col];
|
|
||||||
}
|
|
||||||
|
|
||||||
double epsilon = 1.0 / (totalDocs*avgLength);
|
|
||||||
double sum = 0.0;
|
|
||||||
|
|
||||||
for (int t = 0; t < termCount; t++) {
|
|
||||||
for (int col = 0 ; col < colCount; col++)
|
|
||||||
{
|
|
||||||
int currentX = X_OFFSET + (3 * col * (t + 1));
|
|
||||||
|
|
||||||
|
|
||||||
double termFrequency = matchinfo[currentX];
|
|
||||||
double docsWithTerm = matchinfo[currentX + 2];
|
|
||||||
|
|
||||||
double idf = log(
|
|
||||||
(totalDocs - docsWithTerm + 0.5) /
|
|
||||||
(docsWithTerm + 0.5)
|
|
||||||
);
|
|
||||||
// "...terms appearing in more than half of the corpus will provide negative contributions to the final document score."
|
|
||||||
//http://en.wikipedia.org/wiki/Okapi_BM25
|
|
||||||
|
|
||||||
idf = (idf < 0) ? epsilon : idf; //common terms could have no effect (\epsilon=0.0) or a very small effect (\epsilon=1/NoOfTokens which asymptotes to 0.0)
|
|
||||||
|
|
||||||
double rightSide = (
|
|
||||||
(termFrequency * (K1 + 1)) /
|
|
||||||
(termFrequency + (K1 * (1 - B + (B * (docLength / avgLength)))))
|
|
||||||
);
|
|
||||||
|
|
||||||
rightSide += 1.0;
|
|
||||||
//To comply with BM25+ that solves a lower bounding issue where large documents that match are unfairly scored as
|
|
||||||
//having similar relevancy as short documents that do not contain as many terms
|
|
||||||
//Yuanhua Lv and ChengXiang Zhai. 'Lower-bounding term frequency normalization.' In Proceedings of CIKM'2011, pages 7-16.
|
|
||||||
//http://sifaka.cs.uiuc.edu/~ylv2/pub/cikm11-lowerbound.pdf
|
|
||||||
|
|
||||||
double weight = ((nVal > col+1) ? sqlite3_value_double(apVal[col+1]) : 1.0);
|
|
||||||
|
|
||||||
// double subsequence = matchinfo[S_OFFSET + col];
|
|
||||||
|
|
||||||
sum += (idf * rightSide) * weight; // * subsequence; //useful as a pseudo proximty weighting
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3_result_double(pCtx, sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void okapi_bm25f_kb(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal) {
|
|
||||||
assert(sizeof(int) == 4);
|
|
||||||
|
|
||||||
const unsigned int *matchinfo = (const unsigned int *)sqlite3_value_blob(apVal[0]);
|
|
||||||
|
|
||||||
|
|
||||||
//Setting the default values and ignoring argument based inputs so the extra
|
|
||||||
//arguments can be the column weights instead.
|
|
||||||
if (nVal < 2) sqlite3_result_error(pCtx, "wrong number of arguments to function okapi_bm25_kb(), expected k1 parameter", -1);
|
|
||||||
if (nVal < 3) sqlite3_result_error(pCtx, "wrong number of arguments to function okapi_bm25_kb(), expected b parameter", -1);
|
|
||||||
double K1 = sqlite3_value_double(apVal[1]);
|
|
||||||
double B = sqlite3_value_double(apVal[2]);
|
|
||||||
|
|
||||||
//For a good explanation fo the maths and how to choose these variables
|
|
||||||
//http://stackoverflow.com/a/23161886/622276
|
|
||||||
|
|
||||||
//NOTE: the rearranged order of parameters to match the order presented on
|
|
||||||
//SQLite3 FTS3 documentation 'pcxnals' (http://www.sqlite.org/fts3.html#matchinfo)
|
|
||||||
|
|
||||||
int P_OFFSET = 0;
|
|
||||||
int C_OFFSET = 1;
|
|
||||||
int X_OFFSET = 2;
|
|
||||||
|
|
||||||
int termCount = matchinfo[P_OFFSET];
|
|
||||||
int colCount = matchinfo[C_OFFSET];
|
|
||||||
|
|
||||||
int N_OFFSET = X_OFFSET + 3*termCount*colCount;
|
|
||||||
int A_OFFSET = N_OFFSET + 1;
|
|
||||||
int L_OFFSET = (A_OFFSET + colCount);
|
|
||||||
// int S_OFFSET = (L_OFFSET + colCount); //useful as a pseudo proximity weighting per field/column
|
|
||||||
|
|
||||||
double totalDocs = matchinfo[N_OFFSET];
|
|
||||||
|
|
||||||
double avgLength = 0.0;
|
|
||||||
double docLength = 0.0;
|
|
||||||
|
|
||||||
for (int col = 0; col < colCount; col++)
|
|
||||||
{
|
|
||||||
avgLength += matchinfo[A_OFFSET + col];
|
|
||||||
docLength += matchinfo[L_OFFSET + col];
|
|
||||||
}
|
|
||||||
|
|
||||||
double epsilon = 1.0 / (totalDocs*avgLength);
|
|
||||||
double sum = 0.0;
|
|
||||||
|
|
||||||
for (int t = 0; t < termCount; t++) {
|
|
||||||
for (int col = 0 ; col < colCount; col++)
|
|
||||||
{
|
|
||||||
int currentX = X_OFFSET + (3 * col * (t + 1));
|
|
||||||
|
|
||||||
|
|
||||||
double termFrequency = matchinfo[currentX];
|
|
||||||
double docsWithTerm = matchinfo[currentX + 2];
|
|
||||||
|
|
||||||
double idf = log(
|
|
||||||
(totalDocs - docsWithTerm + 0.5) /
|
|
||||||
(docsWithTerm + 0.5)
|
|
||||||
);
|
|
||||||
// "...terms appearing in more than half of the corpus will provide negative contributions to the final document score."
|
|
||||||
//http://en.wikipedia.org/wiki/Okapi_BM25
|
|
||||||
|
|
||||||
idf = (idf < 0) ? epsilon : idf; //common terms could have no effect (\epsilon=0.0) or a very small effect (\epsilon=1/NoOfTokens which asymptotes to 0.0)
|
|
||||||
|
|
||||||
double rightSide = (
|
|
||||||
(termFrequency * (K1 + 1)) /
|
|
||||||
(termFrequency + (K1 * (1 - B + (B * (docLength / avgLength)))))
|
|
||||||
);
|
|
||||||
|
|
||||||
rightSide += 1.0;
|
|
||||||
//To comply with BM25+ that solves a lower bounding issue where large documents that match are unfairly scored as
|
|
||||||
//having similar relevancy as short documents that do not contain as many terms
|
|
||||||
//Yuanhua Lv and ChengXiang Zhai. 'Lower-bounding term frequency normalization.' In Proceedings of CIKM'2011, pages 7-16.
|
|
||||||
//http://sifaka.cs.uiuc.edu/~ylv2/pub/cikm11-lowerbound.pdf
|
|
||||||
|
|
||||||
double weight = ((nVal > col+3) ? sqlite3_value_double(apVal[col+3]) : 1.0);
|
|
||||||
|
|
||||||
// double subsequence = matchinfo[S_OFFSET + col];
|
|
||||||
|
|
||||||
sum += (idf * rightSide) * weight; // * subsequence; //useful as a pseudo proximty weighting
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3_result_double(pCtx, sum);
|
|
||||||
}
|
|
3
src/libs/3rdparty/sqlite/sqlite.pri
vendored
@@ -3,7 +3,8 @@ INCLUDEPATH *= $$PWD
|
|||||||
HEADERS += $$PWD/sqlite3.h \
|
HEADERS += $$PWD/sqlite3.h \
|
||||||
$$PWD/sqlite3ext.h
|
$$PWD/sqlite3ext.h
|
||||||
|
|
||||||
SOURCES += $$PWD/sqlite3.c
|
SOURCES += $$PWD/sqlite3.c \
|
||||||
|
$$PWD/carray.c
|
||||||
|
|
||||||
gcc {
|
gcc {
|
||||||
QMAKE_CFLAGS_WARN_ON = -w
|
QMAKE_CFLAGS_WARN_ON = -w
|
||||||
|
18951
src/libs/3rdparty/sqlite/sqlite3.c
vendored
623
src/libs/3rdparty/sqlite/sqlite3.h
vendored
20
src/libs/3rdparty/sqlite/sqlite3ext.h
vendored
@@ -322,6 +322,14 @@ struct sqlite3_api_routines {
|
|||||||
/* Version 3.28.0 and later */
|
/* Version 3.28.0 and later */
|
||||||
int (*stmt_isexplain)(sqlite3_stmt*);
|
int (*stmt_isexplain)(sqlite3_stmt*);
|
||||||
int (*value_frombind)(sqlite3_value*);
|
int (*value_frombind)(sqlite3_value*);
|
||||||
|
/* Version 3.30.0 and later */
|
||||||
|
int (*drop_modules)(sqlite3*,const char**);
|
||||||
|
/* Version 3.31.0 and later */
|
||||||
|
sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
|
||||||
|
const char *(*uri_key)(const char*,int);
|
||||||
|
const char *(*filename_database)(const char*);
|
||||||
|
const char *(*filename_journal)(const char*);
|
||||||
|
const char *(*filename_wal)(const char*);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -612,8 +620,16 @@ typedef int (*sqlite3_loadext_entry)(
|
|||||||
/* Version 3.26.0 and later */
|
/* Version 3.26.0 and later */
|
||||||
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
|
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
|
||||||
/* Version 3.28.0 and later */
|
/* Version 3.28.0 and later */
|
||||||
#define sqlite3_stmt_isexplain sqlite3_api->isexplain
|
#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
|
||||||
#define sqlite3_value_frombind sqlite3_api->frombind
|
#define sqlite3_value_frombind sqlite3_api->value_frombind
|
||||||
|
/* Version 3.30.0 and later */
|
||||||
|
#define sqlite3_drop_modules sqlite3_api->drop_modules
|
||||||
|
/* Version 3.31.0 and later */
|
||||||
|
#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
|
||||||
|
#define sqlite3_uri_key sqlite3_api->uri_key
|
||||||
|
#define sqlite3_filename_database sqlite3_api->filename_database
|
||||||
|
#define sqlite3_filename_journal sqlite3_api->filename_journal
|
||||||
|
#define sqlite3_filename_wal sqlite3_api->filename_wal
|
||||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||||
|
|
||||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||||
|
@@ -66,7 +66,7 @@ public:
|
|||||||
Sqlite::Table table;
|
Sqlite::Table table;
|
||||||
table.setUseIfNotExists(true);
|
table.setUseIfNotExists(true);
|
||||||
table.setName("symbols");
|
table.setName("symbols");
|
||||||
table.addColumn("symbolId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
|
table.addColumn("symbolId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||||
const Sqlite::Column &usrColumn = table.addColumn("usr", Sqlite::ColumnType::Text);
|
const Sqlite::Column &usrColumn = table.addColumn("usr", Sqlite::ColumnType::Text);
|
||||||
const Sqlite::Column &symbolNameColumn = table.addColumn("symbolName", Sqlite::ColumnType::Text);
|
const Sqlite::Column &symbolNameColumn = table.addColumn("symbolName", Sqlite::ColumnType::Text);
|
||||||
const Sqlite::Column &symbolKindColumn = table.addColumn("symbolKind", Sqlite::ColumnType::Integer);
|
const Sqlite::Column &symbolKindColumn = table.addColumn("symbolKind", Sqlite::ColumnType::Integer);
|
||||||
@@ -100,7 +100,7 @@ public:
|
|||||||
Sqlite::Table table;
|
Sqlite::Table table;
|
||||||
table.setUseIfNotExists(true);
|
table.setUseIfNotExists(true);
|
||||||
table.setName("sources");
|
table.setName("sources");
|
||||||
table.addColumn("sourceId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
|
table.addColumn("sourceId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||||
const Sqlite::Column &directoryIdColumn = table.addColumn("directoryId", Sqlite::ColumnType::Integer);
|
const Sqlite::Column &directoryIdColumn = table.addColumn("directoryId", Sqlite::ColumnType::Integer);
|
||||||
const Sqlite::Column &sourceNameColumn = table.addColumn("sourceName", Sqlite::ColumnType::Text);
|
const Sqlite::Column &sourceNameColumn = table.addColumn("sourceName", Sqlite::ColumnType::Text);
|
||||||
table.addUniqueIndex({directoryIdColumn, sourceNameColumn});
|
table.addUniqueIndex({directoryIdColumn, sourceNameColumn});
|
||||||
@@ -113,7 +113,7 @@ public:
|
|||||||
Sqlite::Table table;
|
Sqlite::Table table;
|
||||||
table.setUseIfNotExists(true);
|
table.setUseIfNotExists(true);
|
||||||
table.setName("directories");
|
table.setName("directories");
|
||||||
table.addColumn("directoryId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
|
table.addColumn("directoryId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||||
const Sqlite::Column &directoryPathColumn = table.addColumn("directoryPath", Sqlite::ColumnType::Text);
|
const Sqlite::Column &directoryPathColumn = table.addColumn("directoryPath", Sqlite::ColumnType::Text);
|
||||||
table.addUniqueIndex({directoryPathColumn});
|
table.addUniqueIndex({directoryPathColumn});
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ public:
|
|||||||
Sqlite::Table table;
|
Sqlite::Table table;
|
||||||
table.setUseIfNotExists(true);
|
table.setUseIfNotExists(true);
|
||||||
table.setName("projectParts");
|
table.setName("projectParts");
|
||||||
table.addColumn("projectPartId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
|
table.addColumn("projectPartId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||||
const Sqlite::Column &projectPartNameColumn = table.addColumn("projectPartName", Sqlite::ColumnType::Text);
|
const Sqlite::Column &projectPartNameColumn = table.addColumn("projectPartName", Sqlite::ColumnType::Text);
|
||||||
table.addColumn("toolChainArguments", Sqlite::ColumnType::Text);
|
table.addColumn("toolChainArguments", Sqlite::ColumnType::Text);
|
||||||
table.addColumn("compilerMacros", Sqlite::ColumnType::Text);
|
table.addColumn("compilerMacros", Sqlite::ColumnType::Text);
|
||||||
@@ -160,7 +160,7 @@ public:
|
|||||||
Sqlite::Table table;
|
Sqlite::Table table;
|
||||||
table.setUseIfNotExists(true);
|
table.setUseIfNotExists(true);
|
||||||
table.setName("usedMacros");
|
table.setName("usedMacros");
|
||||||
table.addColumn("usedMacroId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
|
table.addColumn("usedMacroId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||||
const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
|
const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
|
||||||
const Sqlite::Column ¯oNameColumn = table.addColumn("macroName", Sqlite::ColumnType::Text);
|
const Sqlite::Column ¯oNameColumn = table.addColumn("macroName", Sqlite::ColumnType::Text);
|
||||||
table.addIndex({sourceIdColumn, macroNameColumn});
|
table.addIndex({sourceIdColumn, macroNameColumn});
|
||||||
@@ -174,9 +174,7 @@ public:
|
|||||||
Sqlite::Table table;
|
Sqlite::Table table;
|
||||||
table.setUseIfNotExists(true);
|
table.setUseIfNotExists(true);
|
||||||
table.setName("fileStatuses");
|
table.setName("fileStatuses");
|
||||||
table.addColumn("sourceId",
|
table.addColumn("sourceId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||||
Sqlite::ColumnType::Integer,
|
|
||||||
Sqlite::Contraint::PrimaryKey);
|
|
||||||
table.addColumn("size", Sqlite::ColumnType::Integer);
|
table.addColumn("size", Sqlite::ColumnType::Integer);
|
||||||
table.addColumn("lastModified", Sqlite::ColumnType::Integer);
|
table.addColumn("lastModified", Sqlite::ColumnType::Integer);
|
||||||
table.addColumn("indexingTimeStamp", Sqlite::ColumnType::Integer);
|
table.addColumn("indexingTimeStamp", Sqlite::ColumnType::Integer);
|
||||||
@@ -201,7 +199,7 @@ public:
|
|||||||
Sqlite::Table table;
|
Sqlite::Table table;
|
||||||
table.setUseIfNotExists(true);
|
table.setUseIfNotExists(true);
|
||||||
table.setName("precompiledHeaders");
|
table.setName("precompiledHeaders");
|
||||||
table.addColumn("projectPartId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
|
table.addColumn("projectPartId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||||
table.addColumn("projectPchPath", Sqlite::ColumnType::Text);
|
table.addColumn("projectPchPath", Sqlite::ColumnType::Text);
|
||||||
table.addColumn("projectPchBuildTime", Sqlite::ColumnType::Integer);
|
table.addColumn("projectPchBuildTime", Sqlite::ColumnType::Integer);
|
||||||
table.addColumn("systemPchPath", Sqlite::ColumnType::Text);
|
table.addColumn("systemPchPath", Sqlite::ColumnType::Text);
|
||||||
|
@@ -53,7 +53,7 @@ inline QString qmlDebugServices(QmlDebugServicesPreset preset)
|
|||||||
case QmlNativeDebuggerServices:
|
case QmlNativeDebuggerServices:
|
||||||
return QStringLiteral("NativeQmlDebugger");
|
return QStringLiteral("NativeQmlDebugger");
|
||||||
case QmlPreviewServices:
|
case QmlPreviewServices:
|
||||||
return QStringLiteral("QmlPreview");
|
return QStringLiteral("QmlPreview,DebugTranslation");
|
||||||
default:
|
default:
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
return QString();
|
return QString();
|
||||||
|
@@ -942,6 +942,9 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
|
|||||||
if (checkTypeForDesignerSupport(typeId))
|
if (checkTypeForDesignerSupport(typeId))
|
||||||
addMessage(WarnUnsupportedTypeInVisualDesigner, typeErrorLocation, typeName);
|
addMessage(WarnUnsupportedTypeInVisualDesigner, typeErrorLocation, typeName);
|
||||||
|
|
||||||
|
if (QFileInfo(_doc->fileName()).baseName() == getRightMostIdentifier(typeId)->name.toString())
|
||||||
|
addMessage(ErrTypeIsInstantiatedRecursively, typeErrorLocation, typeName);
|
||||||
|
|
||||||
if (checkTypeForQmlUiSupport(typeId))
|
if (checkTypeForQmlUiSupport(typeId))
|
||||||
addMessage(ErrUnsupportedTypeInQmlUi, typeErrorLocation, typeName);
|
addMessage(ErrUnsupportedTypeInQmlUi, typeErrorLocation, typeName);
|
||||||
|
|
||||||
|
@@ -245,6 +245,8 @@ StaticAnalysisMessages::StaticAnalysisMessages()
|
|||||||
tr("Duplicate import (%1)."), 1);
|
tr("Duplicate import (%1)."), 1);
|
||||||
newMsg(ErrHitMaximumRecursion, Error,
|
newMsg(ErrHitMaximumRecursion, Error,
|
||||||
tr("Hit maximum recursion limit when visiting AST."));
|
tr("Hit maximum recursion limit when visiting AST."));
|
||||||
|
newMsg(ErrTypeIsInstantiatedRecursively, Error,
|
||||||
|
tr("Type cannot be instantiated recursively (%1)."), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
@@ -89,6 +89,7 @@ enum Type
|
|||||||
MaybeWarnEqualityTypeCoercion = 126,
|
MaybeWarnEqualityTypeCoercion = 126,
|
||||||
WarnConfusingExpressionStatement = 127,
|
WarnConfusingExpressionStatement = 127,
|
||||||
StateCannotHaveChildItem = 128,
|
StateCannotHaveChildItem = 128,
|
||||||
|
ErrTypeIsInstantiatedRecursively = 129,
|
||||||
HintDeclarationsShouldBeAtStartOfFunction = 201,
|
HintDeclarationsShouldBeAtStartOfFunction = 201,
|
||||||
HintOneStatementPerLine = 202,
|
HintOneStatementPerLine = 202,
|
||||||
WarnImperativeCodeNotEditableInVisualDesigner = 203,
|
WarnImperativeCodeNotEditableInVisualDesigner = 203,
|
||||||
|
@@ -1,15 +1,26 @@
|
|||||||
add_qtc_library(Sqlite
|
add_qtc_library(Sqlite
|
||||||
DEFINES
|
PUBLIC_DEFINES
|
||||||
SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS3_PARENTHESIS
|
|
||||||
SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_COLUMN_METADATA
|
|
||||||
BUILD_SQLITE_LIBRARY
|
BUILD_SQLITE_LIBRARY
|
||||||
|
SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS5 SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||||
|
SQLITE_ENABLE_JSON1 SQLITE_DEFAULT_FOREIGN_KEYS=1 SQLITE_TEMP_STORE=2
|
||||||
|
SQLITE_DEFAULT_WAL_SYNCHRONOUS=1 SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_MEMSTATUS=0
|
||||||
|
SQLITE_OMIT_DEPRECATED SQLITE_OMIT_DECLTYPE
|
||||||
|
SQLITE_MAX_EXPR_DEPTH=0 SQLITE_OMIT_SHARED_CACHE SQLITE_USE_ALLOCA
|
||||||
|
SQLITE_ENABLE_MEMORY_MANAGEMENT SQLITE_ENABLE_NULL_TRIM SQLITE_OMIT_EXPLAIN
|
||||||
|
SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_UTF16 SQLITE_DQS=0
|
||||||
|
SQLITE_ENABLE_STAT4 HAVE_ISNAN HAVE_FDATASYNC HAVE_MALLOC_USABLE_SIZE
|
||||||
|
SQLITE_DEFAULT_MMAP_SIZE=268435456 SQLITE_CORE SQLITE_ENABLE_SESSION SQLITE_ENABLE_PREUPDATE_HOOK
|
||||||
|
SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||||
DEPENDS Qt5::Core Threads::Threads ${CMAKE_DL_LIBS}
|
DEPENDS Qt5::Core Threads::Threads ${CMAKE_DL_LIBS}
|
||||||
PUBLIC_INCLUDES
|
PUBLIC_INCLUDES
|
||||||
"${CMAKE_CURRENT_LIST_DIR}"
|
"${CMAKE_CURRENT_LIST_DIR}"
|
||||||
../3rdparty/sqlite
|
../3rdparty/sqlite
|
||||||
SOURCES
|
SOURCES
|
||||||
../3rdparty/sqlite/sqlite3.c
|
../3rdparty/sqlite/sqlite3.c
|
||||||
|
../3rdparty/sqlite/carray.c
|
||||||
|
constraints.h
|
||||||
createtablesqlstatementbuilder.cpp createtablesqlstatementbuilder.h
|
createtablesqlstatementbuilder.cpp createtablesqlstatementbuilder.h
|
||||||
|
lastchangedrowid.h
|
||||||
sqlitebasestatement.cpp sqlitebasestatement.h
|
sqlitebasestatement.cpp sqlitebasestatement.h
|
||||||
sqlitecolumn.h
|
sqlitecolumn.h
|
||||||
sqlitedatabase.cpp sqlitedatabase.h
|
sqlitedatabase.cpp sqlitedatabase.h
|
||||||
@@ -19,6 +30,8 @@ add_qtc_library(Sqlite
|
|||||||
sqliteindex.h
|
sqliteindex.h
|
||||||
sqlitereadstatement.cpp sqlitereadstatement.h
|
sqlitereadstatement.cpp sqlitereadstatement.h
|
||||||
sqlitereadwritestatement.cpp sqlitereadwritestatement.h
|
sqlitereadwritestatement.cpp sqlitereadwritestatement.h
|
||||||
|
sqlitesessionchangeset.cpp sqlitesessionchangeset.h
|
||||||
|
sqlitesessions.cpp sqlitesessions.h
|
||||||
sqlitetable.h
|
sqlitetable.h
|
||||||
sqlitetransaction.h
|
sqlitetransaction.h
|
||||||
sqlitewritestatement.cpp sqlitewritestatement.h
|
sqlitewritestatement.cpp sqlitewritestatement.h
|
||||||
|
193
src/libs/sqlite/constraints.h
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sqliteglobal.h"
|
||||||
|
|
||||||
|
#include <sqlitevalue.h>
|
||||||
|
#include <utils/smallstring.h>
|
||||||
|
#include <utils/variant.h>
|
||||||
|
|
||||||
|
namespace Sqlite {
|
||||||
|
|
||||||
|
class Unique
|
||||||
|
{
|
||||||
|
friend bool operator==(Unique, Unique) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AutoIncrement { No, Yes };
|
||||||
|
|
||||||
|
class PrimaryKey
|
||||||
|
{
|
||||||
|
friend bool operator==(PrimaryKey first, PrimaryKey second)
|
||||||
|
{
|
||||||
|
return first.autoincrement == second.autoincrement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
AutoIncrement autoincrement = AutoIncrement::No;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NotNull
|
||||||
|
{
|
||||||
|
friend bool operator==(NotNull, NotNull) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Check
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Check(Utils::SmallStringView expression)
|
||||||
|
: expression(expression)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend bool operator==(const Check &first, const Check &second)
|
||||||
|
{
|
||||||
|
return first.expression == second.expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Utils::SmallString expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DefaultValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DefaultValue(long long value)
|
||||||
|
: value(value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
DefaultValue(double value)
|
||||||
|
: value(value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
DefaultValue(Utils::SmallStringView value)
|
||||||
|
: value(value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend bool operator==(const DefaultValue &first, const DefaultValue &second)
|
||||||
|
{
|
||||||
|
return first.value == second.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Sqlite::Value value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DefaultExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DefaultExpression(Utils::SmallStringView expression)
|
||||||
|
: expression(expression)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend bool operator==(const DefaultExpression &first, const DefaultExpression &second)
|
||||||
|
{
|
||||||
|
return first.expression == second.expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Utils::SmallString expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Collate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Collate(Utils::SmallStringView collation)
|
||||||
|
: collation(collation)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend bool operator==(const Collate &first, const Collate &second)
|
||||||
|
{
|
||||||
|
return first.collation == second.collation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Utils::SmallString collation;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ForeignKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ForeignKey() = default;
|
||||||
|
ForeignKey(Utils::SmallStringView table,
|
||||||
|
Utils::SmallStringView column,
|
||||||
|
ForeignKeyAction updateAction = {},
|
||||||
|
ForeignKeyAction deleteAction = {},
|
||||||
|
Enforment enforcement = {})
|
||||||
|
: table(table)
|
||||||
|
, column(column)
|
||||||
|
, updateAction(updateAction)
|
||||||
|
, deleteAction(deleteAction)
|
||||||
|
, enforcement(enforcement)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend bool operator==(const ForeignKey &first, const ForeignKey &second)
|
||||||
|
{
|
||||||
|
return first.table == second.table && first.column == second.column
|
||||||
|
&& first.updateAction == second.updateAction
|
||||||
|
&& first.deleteAction == second.deleteAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Utils::SmallString table;
|
||||||
|
Utils::SmallString column;
|
||||||
|
ForeignKeyAction updateAction = {};
|
||||||
|
ForeignKeyAction deleteAction = {};
|
||||||
|
Enforment enforcement = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class GeneratedAlwaysStorage { Stored, Virtual };
|
||||||
|
|
||||||
|
class GeneratedAlways
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GeneratedAlways(Utils::SmallStringView expression, GeneratedAlwaysStorage storage)
|
||||||
|
: expression(expression)
|
||||||
|
, storage(storage)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend bool operator==(const GeneratedAlways &first, const GeneratedAlways &second)
|
||||||
|
{
|
||||||
|
return first.expression == second.expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Utils::SmallString expression;
|
||||||
|
GeneratedAlwaysStorage storage = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
using Constraint = Utils::variant<Unique,
|
||||||
|
PrimaryKey,
|
||||||
|
ForeignKey,
|
||||||
|
NotNull,
|
||||||
|
Check,
|
||||||
|
DefaultValue,
|
||||||
|
DefaultExpression,
|
||||||
|
Collate,
|
||||||
|
GeneratedAlways>;
|
||||||
|
using Constraints = std::vector<Constraint>;
|
||||||
|
|
||||||
|
} // namespace Sqlite
|
@@ -39,16 +39,26 @@ void CreateTableSqlStatementBuilder::setTableName(Utils::SmallString &&tableName
|
|||||||
this->m_tableName = std::move(tableName);
|
this->m_tableName = std::move(tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateTableSqlStatementBuilder::addColumn(Utils::SmallString &&columnName,
|
void CreateTableSqlStatementBuilder::addColumn(Utils::SmallStringView columnName,
|
||||||
ColumnType columnType,
|
ColumnType columnType,
|
||||||
Contraint constraint)
|
Constraints &&constraints)
|
||||||
{
|
{
|
||||||
m_sqlStatementBuilder.clear();
|
m_sqlStatementBuilder.clear();
|
||||||
|
|
||||||
m_columns.emplace_back(std::move(columnName), columnType, constraint);
|
m_columns.emplace_back(Utils::SmallStringView{}, columnName, columnType, std::move(constraints));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateTableSqlStatementBuilder::setColumns(const SqliteColumns &columns)
|
void CreateTableSqlStatementBuilder::addConstraint(TableConstraint &&constraint)
|
||||||
|
{
|
||||||
|
m_tableConstraints.push_back(std::move(constraint));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateTableSqlStatementBuilder::setConstraints(TableConstraints constraints)
|
||||||
|
{
|
||||||
|
m_tableConstraints = std::move(constraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateTableSqlStatementBuilder::setColumns(SqliteColumns columns)
|
||||||
{
|
{
|
||||||
m_sqlStatementBuilder.clear();
|
m_sqlStatementBuilder.clear();
|
||||||
|
|
||||||
@@ -97,20 +107,162 @@ bool CreateTableSqlStatementBuilder::isValid() const
|
|||||||
return m_tableName.hasContent() && !m_columns.empty();
|
return m_tableName.hasContent() && !m_columns.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateTableSqlStatementBuilder::bindColumnDefinitions() const
|
namespace {
|
||||||
|
Utils::SmallStringView actionToText(ForeignKeyAction action)
|
||||||
{
|
{
|
||||||
Utils::SmallStringVector columnDefinitionStrings;
|
switch (action) {
|
||||||
|
case ForeignKeyAction::NoAction:
|
||||||
for (const Column &columns : m_columns) {
|
return "NO ACTION";
|
||||||
Utils::SmallString columnDefinitionString = {columns.name(), " ", columns.typeString()};
|
case ForeignKeyAction::Restrict:
|
||||||
|
return "RESTRICT";
|
||||||
switch (columns.constraint()) {
|
case ForeignKeyAction::SetNull:
|
||||||
case Contraint::PrimaryKey: columnDefinitionString.append(" PRIMARY KEY"); break;
|
return "SET NULL";
|
||||||
case Contraint::Unique: columnDefinitionString.append(" UNIQUE"); break;
|
case ForeignKeyAction::SetDefault:
|
||||||
case Contraint::NoConstraint: break;
|
return "SET DEFAULT";
|
||||||
|
case ForeignKeyAction::Cascade:
|
||||||
|
return "CASCADE";
|
||||||
}
|
}
|
||||||
|
|
||||||
columnDefinitionStrings.push_back(columnDefinitionString);
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
class ContraintsVisiter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ContraintsVisiter(Utils::SmallString &columnDefinitionString)
|
||||||
|
: columnDefinitionString(columnDefinitionString)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void operator()(const Unique &) { columnDefinitionString.append(" UNIQUE"); }
|
||||||
|
|
||||||
|
void operator()(const PrimaryKey &primaryKey)
|
||||||
|
{
|
||||||
|
columnDefinitionString.append(" PRIMARY KEY");
|
||||||
|
if (primaryKey.autoincrement == AutoIncrement::Yes)
|
||||||
|
columnDefinitionString.append(" AUTOINCREMENT");
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const ForeignKey &foreignKey)
|
||||||
|
{
|
||||||
|
columnDefinitionString.append(" REFERENCES ");
|
||||||
|
columnDefinitionString.append(foreignKey.table);
|
||||||
|
|
||||||
|
if (foreignKey.column.hasContent()) {
|
||||||
|
columnDefinitionString.append("(");
|
||||||
|
columnDefinitionString.append(foreignKey.column);
|
||||||
|
columnDefinitionString.append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreignKey.updateAction != ForeignKeyAction::NoAction) {
|
||||||
|
columnDefinitionString.append(" ON UPDATE ");
|
||||||
|
columnDefinitionString.append(actionToText(foreignKey.updateAction));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreignKey.deleteAction != ForeignKeyAction::NoAction) {
|
||||||
|
columnDefinitionString.append(" ON DELETE ");
|
||||||
|
columnDefinitionString.append(actionToText(foreignKey.deleteAction));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreignKey.enforcement == Enforment::Deferred)
|
||||||
|
columnDefinitionString.append(" DEFERRABLE INITIALLY DEFERRED");
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const NotNull &) { columnDefinitionString.append(" NOT NULL"); }
|
||||||
|
|
||||||
|
void operator()(const Check &check)
|
||||||
|
{
|
||||||
|
columnDefinitionString.append(" CHECK (");
|
||||||
|
columnDefinitionString.append(check.expression);
|
||||||
|
columnDefinitionString.append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const DefaultValue &defaultValue)
|
||||||
|
{
|
||||||
|
columnDefinitionString.append(" DEFAULT ");
|
||||||
|
switch (defaultValue.value.type()) {
|
||||||
|
case Sqlite::ValueType::Integer:
|
||||||
|
columnDefinitionString.append(
|
||||||
|
Utils::SmallString::number(defaultValue.value.toInteger()));
|
||||||
|
break;
|
||||||
|
case Sqlite::ValueType::Float:
|
||||||
|
columnDefinitionString.append(Utils::SmallString::number(defaultValue.value.toFloat()));
|
||||||
|
break;
|
||||||
|
case Sqlite::ValueType::String:
|
||||||
|
columnDefinitionString.append("'");
|
||||||
|
columnDefinitionString.append(defaultValue.value.toStringView());
|
||||||
|
columnDefinitionString.append("'");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const DefaultExpression &defaultexpression)
|
||||||
|
{
|
||||||
|
columnDefinitionString.append(" DEFAULT (");
|
||||||
|
columnDefinitionString.append(defaultexpression.expression);
|
||||||
|
columnDefinitionString.append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const Collate &collate)
|
||||||
|
{
|
||||||
|
columnDefinitionString.append(" COLLATE ");
|
||||||
|
columnDefinitionString.append(collate.collation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const GeneratedAlways &generatedAlways)
|
||||||
|
{
|
||||||
|
columnDefinitionString.append(" GENERATED ALWAYS AS (");
|
||||||
|
columnDefinitionString.append(generatedAlways.expression);
|
||||||
|
columnDefinitionString.append(")");
|
||||||
|
|
||||||
|
if (generatedAlways.storage == Sqlite::GeneratedAlwaysStorage::Virtual)
|
||||||
|
columnDefinitionString.append(" VIRTUAL");
|
||||||
|
else
|
||||||
|
columnDefinitionString.append(" STORED");
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::SmallString &columnDefinitionString;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TableContraintsVisiter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TableContraintsVisiter(Utils::SmallString &columnDefinitionString)
|
||||||
|
: columnDefinitionString(columnDefinitionString)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void operator()(const TablePrimaryKey &primaryKey)
|
||||||
|
{
|
||||||
|
columnDefinitionString.append("PRIMARY KEY(");
|
||||||
|
columnDefinitionString.append(primaryKey.columns.join(", "));
|
||||||
|
columnDefinitionString.append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::SmallString &columnDefinitionString;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
void CreateTableSqlStatementBuilder::bindColumnDefinitionsAndTableConstraints() const
|
||||||
|
{
|
||||||
|
Utils::SmallStringVector columnDefinitionStrings;
|
||||||
|
columnDefinitionStrings.reserve(m_columns.size());
|
||||||
|
|
||||||
|
for (const Column &column : m_columns) {
|
||||||
|
Utils::SmallString columnDefinitionString = {column.name, " ", column.typeString()};
|
||||||
|
|
||||||
|
ContraintsVisiter visiter{columnDefinitionString};
|
||||||
|
|
||||||
|
for (const Constraint &constraint : column.constraints)
|
||||||
|
Utils::visit(visiter, constraint);
|
||||||
|
|
||||||
|
columnDefinitionStrings.push_back(std::move(columnDefinitionString));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const TableConstraint &constraint : m_tableConstraints) {
|
||||||
|
Utils::SmallString columnDefinitionString;
|
||||||
|
|
||||||
|
TableContraintsVisiter visiter{columnDefinitionString};
|
||||||
|
Utils::visit(visiter, constraint);
|
||||||
|
|
||||||
|
columnDefinitionStrings.push_back(std::move(columnDefinitionString));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sqlStatementBuilder.bind("$columnDefinitions", columnDefinitionStrings);
|
m_sqlStatementBuilder.bind("$columnDefinitions", columnDefinitionStrings);
|
||||||
@@ -122,7 +274,7 @@ void CreateTableSqlStatementBuilder::bindAll() const
|
|||||||
|
|
||||||
bindTemporary();
|
bindTemporary();
|
||||||
bindIfNotExists();
|
bindIfNotExists();
|
||||||
bindColumnDefinitions();
|
bindColumnDefinitionsAndTableConstraints();
|
||||||
bindWithoutRowId();
|
bindWithoutRowId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "sqlitecolumn.h"
|
#include "sqlitecolumn.h"
|
||||||
#include "sqlstatementbuilder.h"
|
#include "sqlstatementbuilder.h"
|
||||||
|
#include "tableconstraints.h"
|
||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
@@ -36,10 +37,13 @@ public:
|
|||||||
CreateTableSqlStatementBuilder();
|
CreateTableSqlStatementBuilder();
|
||||||
|
|
||||||
void setTableName(Utils::SmallString &&tableName);
|
void setTableName(Utils::SmallString &&tableName);
|
||||||
void addColumn(Utils::SmallString &&columnName,
|
|
||||||
|
void addColumn(Utils::SmallStringView columnName,
|
||||||
ColumnType columnType,
|
ColumnType columnType,
|
||||||
Contraint constraint = Contraint::NoConstraint);
|
Constraints &&constraints = {});
|
||||||
void setColumns(const SqliteColumns &columns);
|
void addConstraint(TableConstraint &&constraint);
|
||||||
|
void setConstraints(TableConstraints constraints);
|
||||||
|
void setColumns(SqliteColumns columns);
|
||||||
void setUseWithoutRowId(bool useWithoutRowId);
|
void setUseWithoutRowId(bool useWithoutRowId);
|
||||||
void setUseIfNotExists(bool useIfNotExists);
|
void setUseIfNotExists(bool useIfNotExists);
|
||||||
void setUseTemporaryTable(bool useTemporaryTable);
|
void setUseTemporaryTable(bool useTemporaryTable);
|
||||||
@@ -52,7 +56,7 @@ public:
|
|||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void bindColumnDefinitions() const;
|
void bindColumnDefinitionsAndTableConstraints() const;
|
||||||
void bindAll() const;
|
void bindAll() const;
|
||||||
void bindWithoutRowId() const;
|
void bindWithoutRowId() const;
|
||||||
void bindIfNotExists() const;
|
void bindIfNotExists() const;
|
||||||
@@ -62,6 +66,7 @@ private:
|
|||||||
mutable SqlStatementBuilder m_sqlStatementBuilder;
|
mutable SqlStatementBuilder m_sqlStatementBuilder;
|
||||||
Utils::SmallString m_tableName;
|
Utils::SmallString m_tableName;
|
||||||
SqliteColumns m_columns;
|
SqliteColumns m_columns;
|
||||||
|
TableConstraints m_tableConstraints;
|
||||||
bool m_useWithoutRowId = false;
|
bool m_useWithoutRowId = false;
|
||||||
bool m_useIfNotExits = false;
|
bool m_useIfNotExits = false;
|
||||||
bool m_useTemporaryTable = false;
|
bool m_useTemporaryTable = false;
|
||||||
|
125
src/libs/sqlite/lastchangedrowid.h
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sqlitedatabaseinterface.h"
|
||||||
|
|
||||||
|
#include <utils/smallstringio.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace Sqlite {
|
||||||
|
|
||||||
|
class LastChangedRowId
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LastChangedRowId(DatabaseInterface &database)
|
||||||
|
: database(database)
|
||||||
|
|
||||||
|
{
|
||||||
|
callback = [=](ChangeType, char const *, char const *, long long rowId) {
|
||||||
|
this->lastRowId = rowId;
|
||||||
|
};
|
||||||
|
|
||||||
|
database.setUpdateHook(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
LastChangedRowId(DatabaseInterface &database, Utils::SmallStringView databaseName)
|
||||||
|
: database(database)
|
||||||
|
|
||||||
|
{
|
||||||
|
callback = [=](ChangeType, char const *database, char const *, long long rowId) {
|
||||||
|
if (databaseName == database)
|
||||||
|
this->lastRowId = rowId;
|
||||||
|
};
|
||||||
|
|
||||||
|
database.setUpdateHook(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
LastChangedRowId(DatabaseInterface &database,
|
||||||
|
Utils::SmallStringView databaseName,
|
||||||
|
Utils::SmallStringView tableName)
|
||||||
|
: database(database)
|
||||||
|
|
||||||
|
{
|
||||||
|
callback = [=](ChangeType, char const *database, char const *table, long long rowId) {
|
||||||
|
if (databaseName == database && tableName == table)
|
||||||
|
this->lastRowId = rowId;
|
||||||
|
};
|
||||||
|
|
||||||
|
database.setUpdateHook(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
LastChangedRowId(DatabaseInterface &database,
|
||||||
|
Utils::SmallStringView databaseName,
|
||||||
|
Utils::SmallStringView tableName,
|
||||||
|
Utils::SmallStringView tableName2)
|
||||||
|
: database(database)
|
||||||
|
|
||||||
|
{
|
||||||
|
callback = [=](ChangeType, char const *database, char const *table, long long rowId) {
|
||||||
|
if (databaseName == database && (tableName == table || tableName2 == table))
|
||||||
|
this->lastRowId = rowId;
|
||||||
|
};
|
||||||
|
|
||||||
|
database.setUpdateHook(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
LastChangedRowId(DatabaseInterface &database,
|
||||||
|
Utils::SmallStringView databaseName,
|
||||||
|
Utils::SmallStringView tableName,
|
||||||
|
Utils::SmallStringView tableName2,
|
||||||
|
Utils::SmallStringView tableName3)
|
||||||
|
: database(database)
|
||||||
|
|
||||||
|
{
|
||||||
|
callback = [=](ChangeType, char const *database, char const *table, long long rowId) {
|
||||||
|
if (databaseName == database
|
||||||
|
&& (tableName == table || tableName2 == table || tableName3 == table))
|
||||||
|
this->lastRowId = rowId;
|
||||||
|
};
|
||||||
|
|
||||||
|
database.setUpdateHook(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
~LastChangedRowId() { database.resetUpdateHook(); }
|
||||||
|
|
||||||
|
long long takeLastRowId()
|
||||||
|
{
|
||||||
|
long long rowId = lastRowId;
|
||||||
|
lastRowId = -1;
|
||||||
|
return rowId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lastRowIdIsValid() { return lastRowId >= 0; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
DatabaseInterface &database;
|
||||||
|
DatabaseInterface::UpdateCallback callback;
|
||||||
|
long long lastRowId = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Sqlite
|
@@ -17,6 +17,8 @@ SOURCES += \
|
|||||||
$$PWD/sqliteglobal.cpp \
|
$$PWD/sqliteglobal.cpp \
|
||||||
$$PWD/sqlitereadstatement.cpp \
|
$$PWD/sqlitereadstatement.cpp \
|
||||||
$$PWD/sqlitereadwritestatement.cpp \
|
$$PWD/sqlitereadwritestatement.cpp \
|
||||||
|
$$PWD/sqlitesessionchangeset.cpp \
|
||||||
|
$$PWD/sqlitesessions.cpp \
|
||||||
$$PWD/sqlitewritestatement.cpp \
|
$$PWD/sqlitewritestatement.cpp \
|
||||||
$$PWD/sqlstatementbuilder.cpp \
|
$$PWD/sqlstatementbuilder.cpp \
|
||||||
$$PWD/utf8string.cpp \
|
$$PWD/utf8string.cpp \
|
||||||
@@ -24,13 +26,18 @@ SOURCES += \
|
|||||||
$$PWD/sqlitedatabase.cpp \
|
$$PWD/sqlitedatabase.cpp \
|
||||||
$$PWD/sqlitebasestatement.cpp
|
$$PWD/sqlitebasestatement.cpp
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
$$PWD/constraints.h \
|
||||||
|
$$PWD/tableconstraints.h \
|
||||||
$$PWD/createtablesqlstatementbuilder.h \
|
$$PWD/createtablesqlstatementbuilder.h \
|
||||||
|
$$PWD/lastchangedrowid.h \
|
||||||
$$PWD/sqlitedatabasebackend.h \
|
$$PWD/sqlitedatabasebackend.h \
|
||||||
$$PWD/sqlitedatabaseinterface.h \
|
$$PWD/sqlitedatabaseinterface.h \
|
||||||
$$PWD/sqliteexception.h \
|
$$PWD/sqliteexception.h \
|
||||||
$$PWD/sqliteglobal.h \
|
$$PWD/sqliteglobal.h \
|
||||||
$$PWD/sqlitereadstatement.h \
|
$$PWD/sqlitereadstatement.h \
|
||||||
$$PWD/sqlitereadwritestatement.h \
|
$$PWD/sqlitereadwritestatement.h \
|
||||||
|
$$PWD/sqlitesessionchangeset.h \
|
||||||
|
$$PWD/sqlitesessions.h \
|
||||||
$$PWD/sqlitetransaction.h \
|
$$PWD/sqlitetransaction.h \
|
||||||
$$PWD/sqlitevalue.h \
|
$$PWD/sqlitevalue.h \
|
||||||
$$PWD/sqlitewritestatement.h \
|
$$PWD/sqlitewritestatement.h \
|
||||||
@@ -44,8 +51,18 @@ HEADERS += \
|
|||||||
$$PWD/sqliteindex.h \
|
$$PWD/sqliteindex.h \
|
||||||
$$PWD/sqlitebasestatement.h
|
$$PWD/sqlitebasestatement.h
|
||||||
|
|
||||||
DEFINES += SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS3_PARENTHESIS \
|
DEFINES += SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS5 SQLITE_ENABLE_UNLOCK_NOTIFY \
|
||||||
SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_COLUMN_METADATA SQLITE_ENABLE_JSON1
|
SQLITE_ENABLE_JSON1 SQLITE_DEFAULT_FOREIGN_KEYS=1 SQLITE_TEMP_STORE=2 \
|
||||||
|
SQLITE_DEFAULT_WAL_SYNCHRONOUS=1 SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_MEMSTATUS=0 \
|
||||||
|
SQLITE_OMIT_DEPRECATED SQLITE_OMIT_DECLTYPE \
|
||||||
|
SQLITE_MAX_EXPR_DEPTH=0 SQLITE_OMIT_SHARED_CACHE SQLITE_USE_ALLOCA \
|
||||||
|
SQLITE_ENABLE_MEMORY_MANAGEMENT SQLITE_ENABLE_NULL_TRIM SQLITE_OMIT_EXPLAIN \
|
||||||
|
SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_UTF16 SQLITE_DQS=0 \
|
||||||
|
SQLITE_ENABLE_STAT4 HAVE_ISNAN HAVE_FDATASYNC HAVE_MALLOC_USABLE_SIZE \
|
||||||
|
SQLITE_DEFAULT_MMAP_SIZE=268435456 SQLITE_CORE SQLITE_ENABLE_SESSION SQLITE_ENABLE_PREUPDATE_HOOK \
|
||||||
|
SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||||
|
|
||||||
|
CONFIG(debug, debug|release): DEFINES += SQLITE_ENABLE_API_ARMOR
|
||||||
|
|
||||||
OTHER_FILES += README.md
|
OTHER_FILES += README.md
|
||||||
|
|
||||||
|
@@ -3,7 +3,5 @@ win32:QMAKE_CXXFLAGS_DEBUG += -O2
|
|||||||
|
|
||||||
include(../../qtcreatorlibrary.pri)
|
include(../../qtcreatorlibrary.pri)
|
||||||
|
|
||||||
win32:DEFINES += SQLITE_API=__declspec(dllexport)
|
|
||||||
unix:DEFINES += SQLITE_API=\"__attribute__((visibility(\\\"default\\\")))\"
|
|
||||||
|
|
||||||
include(sqlite-lib.pri)
|
include(sqlite-lib.pri)
|
||||||
|
@@ -6,12 +6,16 @@ QtcLibrary {
|
|||||||
cpp.includePaths: base.concat(["../3rdparty/sqlite", "."])
|
cpp.includePaths: base.concat(["../3rdparty/sqlite", "."])
|
||||||
cpp.defines: base.concat([
|
cpp.defines: base.concat([
|
||||||
"BUILD_SQLITE_LIBRARY",
|
"BUILD_SQLITE_LIBRARY",
|
||||||
"SQLITE_THREADSAFE=2",
|
"SQLITE_THREADSAFE=2", "SQLITE_ENABLE_FTS5", "SQLITE_ENABLE_UNLOCK_NOTIFY",
|
||||||
"SQLITE_ENABLE_FTS4",
|
"SQLITE_ENABLE_JSON1", "SQLITE_DEFAULT_FOREIGN_KEYS=1", "SQLITE_TEMP_STORE=2",
|
||||||
"SQLITE_ENABLE_FTS3_PARENTHESIS",
|
"SQLITE_DEFAULT_WAL_SYNCHRONOUS=1", "SQLITE_MAX_WORKER_THREADS", "SQLITE_DEFAULT_MEMSTATUS=0",
|
||||||
"SQLITE_ENABLE_UNLOCK_NOTIFY",
|
"SQLITE_OMIT_DEPRECATED", "SQLITE_OMIT_DECLTYPE",
|
||||||
"SQLITE_ENABLE_COLUMN_METADATA",
|
"SQLITE_MAX_EXPR_DEPTH=0", "SQLITE_OMIT_SHARED_CACHE", "SQLITE_USE_ALLOCA",
|
||||||
"SQLITE_ENABLE_JSON1"
|
"SQLITE_ENABLE_MEMORY_MANAGEMENT", "SQLITE_ENABLE_NULL_TRIM", "SQLITE_OMIT_EXPLAIN",
|
||||||
|
"SQLITE_OMIT_LOAD_EXTENSION", "SQLITE_OMIT_UTF16", "SQLITE_DQS=0",
|
||||||
|
"SQLITE_ENABLE_STAT4", "HAVE_ISNAN", "HAVE_FDATASYNC", "HAVE_MALLOC_USABLE_SIZE",
|
||||||
|
"SQLITE_DEFAULT_MMAP_SIZE=268435456", "SQLITE_CORE", "SQLITE_ENABLE_SESSION", "SQLITE_ENABLE_PREUPDATE_HOOK",
|
||||||
|
"SQLITE_LIKE_DOESNT_MATCH_BLOBS"
|
||||||
])
|
])
|
||||||
cpp.optimization: "fast"
|
cpp.optimization: "fast"
|
||||||
cpp.dynamicLibraries: base.concat((qbs.targetOS.contains("unix") && !qbs.targetOS.contains("bsd"))
|
cpp.dynamicLibraries: base.concat((qbs.targetOS.contains("unix") && !qbs.targetOS.contains("bsd"))
|
||||||
@@ -26,6 +30,7 @@ QtcLibrary {
|
|||||||
"sqlite3.c",
|
"sqlite3.c",
|
||||||
"sqlite3.h",
|
"sqlite3.h",
|
||||||
"sqlite3ext.h",
|
"sqlite3ext.h",
|
||||||
|
"carray.c"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -41,11 +41,10 @@
|
|||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database)
|
BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database)
|
||||||
: m_compiledStatement(nullptr, deleteCompiledStatement),
|
: m_compiledStatement(nullptr, deleteCompiledStatement)
|
||||||
m_database(database),
|
, m_database(database)
|
||||||
m_bindingParameterCount(0),
|
, m_bindingParameterCount(0)
|
||||||
m_columnCount(0),
|
, m_columnCount(0)
|
||||||
m_isReadyToFetchValues(false)
|
|
||||||
{
|
{
|
||||||
prepare(sqlStatement);
|
prepare(sqlStatement);
|
||||||
setBindingParameterCount();
|
setBindingParameterCount();
|
||||||
@@ -107,11 +106,8 @@ void BaseStatement::reset() const
|
|||||||
{
|
{
|
||||||
int resultCode = sqlite3_reset(m_compiledStatement.get());
|
int resultCode = sqlite3_reset(m_compiledStatement.get());
|
||||||
|
|
||||||
if (resultCode != SQLITE_OK) {
|
if (resultCode != SQLITE_OK)
|
||||||
checkForResetError(resultCode);
|
checkForResetError(resultCode);
|
||||||
|
|
||||||
m_isReadyToFetchValues = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseStatement::next() const
|
bool BaseStatement::next() const
|
||||||
@@ -127,8 +123,6 @@ bool BaseStatement::next() const
|
|||||||
|
|
||||||
} while (resultCode == SQLITE_LOCKED);
|
} while (resultCode == SQLITE_LOCKED);
|
||||||
|
|
||||||
setIfIsReadyToFetchValues(resultCode);
|
|
||||||
|
|
||||||
if (resultCode == SQLITE_ROW)
|
if (resultCode == SQLITE_ROW)
|
||||||
return true;
|
return true;
|
||||||
else if (resultCode == SQLITE_DONE)
|
else if (resultCode == SQLITE_DONE)
|
||||||
@@ -147,15 +141,11 @@ int BaseStatement::columnCount() const
|
|||||||
return m_columnCount;
|
return m_columnCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::SmallStringVector BaseStatement::columnNames() const
|
void BaseStatement::bind(int index, NullValue)
|
||||||
{
|
{
|
||||||
Utils::SmallStringVector columnNames;
|
int resultCode = sqlite3_bind_null(m_compiledStatement.get(), index);
|
||||||
int columnCount = BaseStatement::columnCount();
|
if (resultCode != SQLITE_OK)
|
||||||
columnNames.reserve(std::size_t(columnCount));
|
checkForBindingError(resultCode);
|
||||||
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
|
|
||||||
columnNames.emplace_back(sqlite3_column_origin_name(m_compiledStatement.get(), columnIndex));
|
|
||||||
|
|
||||||
return columnNames;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseStatement::bind(int index, int value)
|
void BaseStatement::bind(int index, int value)
|
||||||
@@ -179,6 +169,17 @@ void BaseStatement::bind(int index, double value)
|
|||||||
checkForBindingError(resultCode);
|
checkForBindingError(resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseStatement::bind(int index, void *pointer)
|
||||||
|
{
|
||||||
|
int resultCode = sqlite3_bind_pointer(m_compiledStatement.get(),
|
||||||
|
index,
|
||||||
|
pointer,
|
||||||
|
"carray",
|
||||||
|
nullptr);
|
||||||
|
if (resultCode != SQLITE_OK)
|
||||||
|
checkForBindingError(resultCode);
|
||||||
|
}
|
||||||
|
|
||||||
void BaseStatement::bind(int index, Utils::SmallStringView text)
|
void BaseStatement::bind(int index, Utils::SmallStringView text)
|
||||||
{
|
{
|
||||||
int resultCode = sqlite3_bind_text(m_compiledStatement.get(),
|
int resultCode = sqlite3_bind_text(m_compiledStatement.get(),
|
||||||
@@ -190,6 +191,17 @@ void BaseStatement::bind(int index, Utils::SmallStringView text)
|
|||||||
checkForBindingError(resultCode);
|
checkForBindingError(resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseStatement::bind(int index, Utils::span<const byte> bytes)
|
||||||
|
{
|
||||||
|
int resultCode = sqlite3_bind_blob64(m_compiledStatement.get(),
|
||||||
|
index,
|
||||||
|
bytes.data(),
|
||||||
|
static_cast<long long>(bytes.size()),
|
||||||
|
SQLITE_STATIC);
|
||||||
|
if (resultCode != SQLITE_OK)
|
||||||
|
checkForBindingError(resultCode);
|
||||||
|
}
|
||||||
|
|
||||||
void BaseStatement::bind(int index, const Value &value)
|
void BaseStatement::bind(int index, const Value &value)
|
||||||
{
|
{
|
||||||
switch (value.type()) {
|
switch (value.type()) {
|
||||||
@@ -205,25 +217,6 @@ void BaseStatement::bind(int index, const Value &value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
void BaseStatement::bind(Utils::SmallStringView name, Type value)
|
|
||||||
{
|
|
||||||
int index = bindingIndexForName(name);
|
|
||||||
checkBindingName(index);
|
|
||||||
bind(index, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, int value);
|
|
||||||
template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long value);
|
|
||||||
template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long long value);
|
|
||||||
template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, double value);
|
|
||||||
template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text);
|
|
||||||
|
|
||||||
int BaseStatement::bindingIndexForName(Utils::SmallStringView name) const
|
|
||||||
{
|
|
||||||
return sqlite3_bind_parameter_index(m_compiledStatement.get(), name.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseStatement::prepare(Utils::SmallStringView sqlStatement)
|
void BaseStatement::prepare(Utils::SmallStringView sqlStatement)
|
||||||
{
|
{
|
||||||
int resultCode;
|
int resultCode;
|
||||||
@@ -252,11 +245,6 @@ sqlite3 *BaseStatement::sqliteDatabaseHandle() const
|
|||||||
return m_database.backend().sqliteDatabaseHandle();
|
return m_database.backend().sqliteDatabaseHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEncoding BaseStatement::databaseTextEncoding()
|
|
||||||
{
|
|
||||||
return m_database.backend().textEncoding();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseStatement::checkForStepError(int resultCode) const
|
void BaseStatement::checkForStepError(int resultCode) const
|
||||||
{
|
{
|
||||||
switch (resultCode) {
|
switch (resultCode) {
|
||||||
@@ -305,33 +293,10 @@ void BaseStatement::checkForBindingError(int resultCode) const
|
|||||||
throwUnknowError("SqliteStatement::bind: unknown error has happened");
|
throwUnknowError("SqliteStatement::bind: unknown error has happened");
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseStatement::setIfIsReadyToFetchValues(int resultCode) const
|
void BaseStatement::checkColumnCount(int columnCount) const
|
||||||
{
|
{
|
||||||
if (resultCode == SQLITE_ROW)
|
if (columnCount != m_columnCount)
|
||||||
m_isReadyToFetchValues = true;
|
throw ColumnCountDoesNotMatch("SqliteStatement::values: column count does not match!");
|
||||||
else
|
|
||||||
m_isReadyToFetchValues = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseStatement::checkIfIsReadyToFetchValues() const
|
|
||||||
{
|
|
||||||
if (!m_isReadyToFetchValues)
|
|
||||||
throwNoValuesToFetch("SqliteStatement::value: there are no values to fetch!");
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseStatement::checkColumnsAreValid(const std::vector<int> &columns) const
|
|
||||||
{
|
|
||||||
for (int column : columns) {
|
|
||||||
if (column < 0 || column >= m_columnCount)
|
|
||||||
throwInvalidColumnFetched("SqliteStatement::values: column index out of bound!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseStatement::checkColumnIsValid(int column) const
|
|
||||||
{
|
|
||||||
if (column < 0 || column >= m_columnCount)
|
|
||||||
throwInvalidColumnFetched("SqliteStatement::values: column index out of bound!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseStatement::checkBindingName(int index) const
|
void BaseStatement::checkBindingName(int index) const
|
||||||
@@ -393,11 +358,6 @@ void BaseStatement::throwNoValuesToFetch(const char *whatHasHappened) const
|
|||||||
throw NoValuesToFetch(whatHasHappened);
|
throw NoValuesToFetch(whatHasHappened);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseStatement::throwInvalidColumnFetched(const char *whatHasHappened) const
|
|
||||||
{
|
|
||||||
throw InvalidColumnFetched(whatHasHappened);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseStatement::throwBindingIndexIsOutOfRange(const char *whatHasHappened) const
|
void BaseStatement::throwBindingIndexIsOutOfRange(const char *whatHasHappened) const
|
||||||
{
|
{
|
||||||
throw BindingIndexIsOutOfRange(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
|
throw BindingIndexIsOutOfRange(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
|
||||||
@@ -431,8 +391,9 @@ Database &BaseStatement::database() const
|
|||||||
return m_database;
|
return m_database;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename StringType>
|
namespace {
|
||||||
static StringType textForColumn(sqlite3_stmt *sqlStatment, int column)
|
template<typename StringType>
|
||||||
|
StringType textForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||||
{
|
{
|
||||||
const char *text = reinterpret_cast<const char*>(sqlite3_column_text(sqlStatment, column));
|
const char *text = reinterpret_cast<const char*>(sqlite3_column_text(sqlStatment, column));
|
||||||
std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column));
|
std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column));
|
||||||
@@ -440,25 +401,43 @@ static StringType textForColumn(sqlite3_stmt *sqlStatment, int column)
|
|||||||
return StringType(text, size);
|
return StringType(text, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename StringType>
|
Utils::span<const byte> blobForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||||
static StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column)
|
{
|
||||||
|
const byte *blob = reinterpret_cast<const byte *>(sqlite3_column_blob(sqlStatment, column));
|
||||||
|
std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column));
|
||||||
|
|
||||||
|
return {blob, size};
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::span<const byte> convertToBlobForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||||
|
{
|
||||||
|
int dataType = sqlite3_column_type(sqlStatment, column);
|
||||||
|
if (dataType == SQLITE_BLOB)
|
||||||
|
return blobForColumn(sqlStatment, column);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename StringType>
|
||||||
|
StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||||
{
|
{
|
||||||
int dataType = sqlite3_column_type(sqlStatment, column);
|
int dataType = sqlite3_column_type(sqlStatment, column);
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
case SQLITE_INTEGER:
|
case SQLITE_INTEGER:
|
||||||
case SQLITE_FLOAT:
|
case SQLITE_FLOAT:
|
||||||
case SQLITE3_TEXT: return textForColumn<StringType>(sqlStatment, column);
|
case SQLITE3_TEXT:
|
||||||
|
return textForColumn<StringType>(sqlStatment, column);
|
||||||
case SQLITE_BLOB:
|
case SQLITE_BLOB:
|
||||||
case SQLITE_NULL: break;
|
case SQLITE_NULL:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return StringType{"", 0};
|
return StringType{"", 0};
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
int BaseStatement::fetchIntValue(int column) const
|
int BaseStatement::fetchIntValue(int column) const
|
||||||
{
|
{
|
||||||
checkIfIsReadyToFetchValues();
|
|
||||||
checkColumnIsValid(column);
|
|
||||||
return sqlite3_column_int(m_compiledStatement.get(), column);
|
return sqlite3_column_int(m_compiledStatement.get(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,8 +460,6 @@ long BaseStatement::fetchValue<long>(int column) const
|
|||||||
|
|
||||||
long long BaseStatement::fetchLongLongValue(int column) const
|
long long BaseStatement::fetchLongLongValue(int column) const
|
||||||
{
|
{
|
||||||
checkIfIsReadyToFetchValues();
|
|
||||||
checkColumnIsValid(column);
|
|
||||||
return sqlite3_column_int64(m_compiledStatement.get(), column);
|
return sqlite3_column_int64(m_compiledStatement.get(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,11 +471,14 @@ long long BaseStatement::fetchValue<long long>(int column) const
|
|||||||
|
|
||||||
double BaseStatement::fetchDoubleValue(int column) const
|
double BaseStatement::fetchDoubleValue(int column) const
|
||||||
{
|
{
|
||||||
checkIfIsReadyToFetchValues();
|
|
||||||
checkColumnIsValid(column);
|
|
||||||
return sqlite3_column_double(m_compiledStatement.get(), column);
|
return sqlite3_column_double(m_compiledStatement.get(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Utils::span<const byte> BaseStatement::fetchBlobValue(int column) const
|
||||||
|
{
|
||||||
|
return convertToBlobForColumn(m_compiledStatement.get(), column);
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
double BaseStatement::fetchValue<double>(int column) const
|
double BaseStatement::fetchValue<double>(int column) const
|
||||||
{
|
{
|
||||||
@@ -508,8 +488,6 @@ double BaseStatement::fetchValue<double>(int column) const
|
|||||||
template<typename StringType>
|
template<typename StringType>
|
||||||
StringType BaseStatement::fetchValue(int column) const
|
StringType BaseStatement::fetchValue(int column) const
|
||||||
{
|
{
|
||||||
checkIfIsReadyToFetchValues();
|
|
||||||
checkColumnIsValid(column);
|
|
||||||
return convertToTextForColumn<StringType>(m_compiledStatement.get(), column);
|
return convertToTextForColumn<StringType>(m_compiledStatement.get(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,6 +507,8 @@ ValueView BaseStatement::fetchValueView(int column) const
|
|||||||
{
|
{
|
||||||
int dataType = sqlite3_column_type(m_compiledStatement.get(), column);
|
int dataType = sqlite3_column_type(m_compiledStatement.get(), column);
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
|
case SQLITE_NULL:
|
||||||
|
return ValueView::create(NullValue{});
|
||||||
case SQLITE_INTEGER:
|
case SQLITE_INTEGER:
|
||||||
return ValueView::create(fetchLongLongValue(column));
|
return ValueView::create(fetchLongLongValue(column));
|
||||||
case SQLITE_FLOAT:
|
case SQLITE_FLOAT:
|
||||||
@@ -536,11 +516,10 @@ ValueView BaseStatement::fetchValueView(int column) const
|
|||||||
case SQLITE3_TEXT:
|
case SQLITE3_TEXT:
|
||||||
return ValueView::create(fetchValue<Utils::SmallStringView>(column));
|
return ValueView::create(fetchValue<Utils::SmallStringView>(column));
|
||||||
case SQLITE_BLOB:
|
case SQLITE_BLOB:
|
||||||
case SQLITE_NULL:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ValueView::create(0LL);
|
return ValueView::create(NullValue{});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
#include <utils/smallstringvector.h>
|
#include <utils/smallstringvector.h>
|
||||||
|
|
||||||
#include <utils/optional.h>
|
#include <utils/optional.h>
|
||||||
|
#include <utils/span.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -69,16 +70,19 @@ public:
|
|||||||
double fetchDoubleValue(int column) const;
|
double fetchDoubleValue(int column) const;
|
||||||
Utils::SmallStringView fetchSmallStringViewValue(int column) const;
|
Utils::SmallStringView fetchSmallStringViewValue(int column) const;
|
||||||
ValueView fetchValueView(int column) const;
|
ValueView fetchValueView(int column) const;
|
||||||
|
Utils::span<const byte> fetchBlobValue(int column) const;
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
Type fetchValue(int column) const;
|
Type fetchValue(int column) const;
|
||||||
int columnCount() const;
|
int columnCount() const;
|
||||||
Utils::SmallStringVector columnNames() const;
|
|
||||||
|
|
||||||
|
void bind(int index, NullValue);
|
||||||
void bind(int index, int fetchValue);
|
void bind(int index, int fetchValue);
|
||||||
void bind(int index, long long fetchValue);
|
void bind(int index, long long fetchValue);
|
||||||
void bind(int index, double fetchValue);
|
void bind(int index, double fetchValue);
|
||||||
|
void bind(int index, void *pointer);
|
||||||
void bind(int index, Utils::SmallStringView fetchValue);
|
void bind(int index, Utils::SmallStringView fetchValue);
|
||||||
void bind(int index, const Value &fetchValue);
|
void bind(int index, const Value &fetchValue);
|
||||||
|
void bind(int index, Utils::span<const byte> bytes);
|
||||||
|
|
||||||
void bind(int index, uint value) { bind(index, static_cast<long long>(value)); }
|
void bind(int index, uint value) { bind(index, static_cast<long long>(value)); }
|
||||||
|
|
||||||
@@ -87,25 +91,17 @@ public:
|
|||||||
bind(index, static_cast<long long>(value));
|
bind(index, static_cast<long long>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
void bind(Utils::SmallStringView name, Type fetchValue);
|
|
||||||
|
|
||||||
int bindingIndexForName(Utils::SmallStringView name) const;
|
|
||||||
|
|
||||||
void prepare(Utils::SmallStringView sqlStatement);
|
void prepare(Utils::SmallStringView sqlStatement);
|
||||||
void waitForUnlockNotify() const;
|
void waitForUnlockNotify() const;
|
||||||
|
|
||||||
sqlite3 *sqliteDatabaseHandle() const;
|
sqlite3 *sqliteDatabaseHandle() const;
|
||||||
TextEncoding databaseTextEncoding();
|
|
||||||
|
|
||||||
[[noreturn]] void checkForStepError(int resultCode) const;
|
[[noreturn]] void checkForStepError(int resultCode) const;
|
||||||
[[noreturn]] void checkForResetError(int resultCode) const;
|
[[noreturn]] void checkForResetError(int resultCode) const;
|
||||||
[[noreturn]] void checkForPrepareError(int resultCode) const;
|
[[noreturn]] void checkForPrepareError(int resultCode) const;
|
||||||
[[noreturn]] void checkForBindingError(int resultCode) const;
|
[[noreturn]] void checkForBindingError(int resultCode) const;
|
||||||
void setIfIsReadyToFetchValues(int resultCode) const;
|
void setIfIsReadyToFetchValues(int resultCode) const;
|
||||||
void checkIfIsReadyToFetchValues() const;
|
void checkColumnCount(int columnCount) const;
|
||||||
void checkColumnsAreValid(const std::vector<int> &columns) const;
|
|
||||||
void checkColumnIsValid(int column) const;
|
|
||||||
void checkBindingName(int index) const;
|
void checkBindingName(int index) const;
|
||||||
void setBindingParameterCount();
|
void setBindingParameterCount();
|
||||||
void setColumnCount();
|
void setColumnCount();
|
||||||
@@ -130,19 +126,12 @@ protected:
|
|||||||
~BaseStatement() = default;
|
~BaseStatement() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<sqlite3_stmt, void (*)(sqlite3_stmt*)> m_compiledStatement;
|
std::unique_ptr<sqlite3_stmt, void (*)(sqlite3_stmt *)> m_compiledStatement;
|
||||||
Database &m_database;
|
Database &m_database;
|
||||||
int m_bindingParameterCount;
|
int m_bindingParameterCount;
|
||||||
int m_columnCount;
|
int m_columnCount;
|
||||||
mutable bool m_isReadyToFetchValues;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, int value);
|
|
||||||
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long value);
|
|
||||||
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long long value);
|
|
||||||
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, double value);
|
|
||||||
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text);
|
|
||||||
|
|
||||||
template <> SQLITE_EXPORT int BaseStatement::fetchValue<int>(int column) const;
|
template <> SQLITE_EXPORT int BaseStatement::fetchValue<int>(int column) const;
|
||||||
template <> SQLITE_EXPORT long BaseStatement::fetchValue<long>(int column) const;
|
template <> SQLITE_EXPORT long BaseStatement::fetchValue<long>(int column) const;
|
||||||
template <> SQLITE_EXPORT long long BaseStatement::fetchValue<long long>(int column) const;
|
template <> SQLITE_EXPORT long long BaseStatement::fetchValue<long long>(int column) const;
|
||||||
@@ -184,32 +173,21 @@ public:
|
|||||||
resetter.reset();
|
resetter.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... ValueType>
|
|
||||||
void bindNameValues(const ValueType&... values)
|
|
||||||
{
|
|
||||||
bindValuesByName(values...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... ValueType>
|
|
||||||
void writeNamed(const ValueType&... values)
|
|
||||||
{
|
|
||||||
Resetter resetter{*this};
|
|
||||||
bindValuesByName(values...);
|
|
||||||
BaseStatement::next();
|
|
||||||
resetter.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename ResultType,
|
template <typename ResultType,
|
||||||
int ResultTypeCount = 1>
|
int ResultTypeCount = 1>
|
||||||
std::vector<ResultType> values(std::size_t reserveSize)
|
std::vector<ResultType> values(std::size_t reserveSize)
|
||||||
{
|
{
|
||||||
|
BaseStatement::checkColumnCount(ResultTypeCount);
|
||||||
|
|
||||||
Resetter resetter{*this};
|
Resetter resetter{*this};
|
||||||
std::vector<ResultType> resultValues;
|
std::vector<ResultType> resultValues;
|
||||||
resultValues.reserve(reserveSize);
|
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
|
||||||
|
|
||||||
while (BaseStatement::next())
|
while (BaseStatement::next())
|
||||||
emplaceBackValues<ResultTypeCount>(resultValues);
|
emplaceBackValues<ResultTypeCount>(resultValues);
|
||||||
|
|
||||||
|
setMaximumResultCount(resultValues.size());
|
||||||
|
|
||||||
resetter.reset();
|
resetter.reset();
|
||||||
|
|
||||||
return resultValues;
|
return resultValues;
|
||||||
@@ -220,15 +198,19 @@ public:
|
|||||||
typename... QueryTypes>
|
typename... QueryTypes>
|
||||||
std::vector<ResultType> values(std::size_t reserveSize, const QueryTypes&... queryValues)
|
std::vector<ResultType> values(std::size_t reserveSize, const QueryTypes&... queryValues)
|
||||||
{
|
{
|
||||||
|
BaseStatement::checkColumnCount(ResultTypeCount);
|
||||||
|
|
||||||
Resetter resetter{*this};
|
Resetter resetter{*this};
|
||||||
std::vector<ResultType> resultValues;
|
std::vector<ResultType> resultValues;
|
||||||
resultValues.reserve(reserveSize);
|
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
|
||||||
|
|
||||||
bindValues(queryValues...);
|
bindValues(queryValues...);
|
||||||
|
|
||||||
while (BaseStatement::next())
|
while (BaseStatement::next())
|
||||||
emplaceBackValues<ResultTypeCount>(resultValues);
|
emplaceBackValues<ResultTypeCount>(resultValues);
|
||||||
|
|
||||||
|
setMaximumResultCount(resultValues.size());
|
||||||
|
|
||||||
resetter.reset();
|
resetter.reset();
|
||||||
|
|
||||||
return resultValues;
|
return resultValues;
|
||||||
@@ -240,8 +222,10 @@ public:
|
|||||||
std::vector<ResultType> values(std::size_t reserveSize,
|
std::vector<ResultType> values(std::size_t reserveSize,
|
||||||
const std::vector<QueryElementType> &queryValues)
|
const std::vector<QueryElementType> &queryValues)
|
||||||
{
|
{
|
||||||
|
BaseStatement::checkColumnCount(ResultTypeCount);
|
||||||
|
|
||||||
std::vector<ResultType> resultValues;
|
std::vector<ResultType> resultValues;
|
||||||
resultValues.reserve(reserveSize);
|
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
|
||||||
|
|
||||||
for (const QueryElementType &queryValue : queryValues) {
|
for (const QueryElementType &queryValue : queryValues) {
|
||||||
Resetter resetter{*this};
|
Resetter resetter{*this};
|
||||||
@@ -250,6 +234,8 @@ public:
|
|||||||
while (BaseStatement::next())
|
while (BaseStatement::next())
|
||||||
emplaceBackValues<ResultTypeCount>(resultValues);
|
emplaceBackValues<ResultTypeCount>(resultValues);
|
||||||
|
|
||||||
|
setMaximumResultCount(resultValues.size());
|
||||||
|
|
||||||
resetter.reset();
|
resetter.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,9 +248,11 @@ public:
|
|||||||
std::vector<ResultType> values(std::size_t reserveSize,
|
std::vector<ResultType> values(std::size_t reserveSize,
|
||||||
const std::vector<std::tuple<QueryElementTypes...>> &queryTuples)
|
const std::vector<std::tuple<QueryElementTypes...>> &queryTuples)
|
||||||
{
|
{
|
||||||
|
BaseStatement::checkColumnCount(ResultTypeCount);
|
||||||
|
|
||||||
using Container = std::vector<ResultType>;
|
using Container = std::vector<ResultType>;
|
||||||
Container resultValues;
|
Container resultValues;
|
||||||
resultValues.reserve(reserveSize);
|
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
|
||||||
|
|
||||||
for (const auto &queryTuple : queryTuples) {
|
for (const auto &queryTuple : queryTuples) {
|
||||||
Resetter resetter{*this};
|
Resetter resetter{*this};
|
||||||
@@ -273,6 +261,8 @@ public:
|
|||||||
while (BaseStatement::next())
|
while (BaseStatement::next())
|
||||||
emplaceBackValues<ResultTypeCount>(resultValues);
|
emplaceBackValues<ResultTypeCount>(resultValues);
|
||||||
|
|
||||||
|
setMaximumResultCount(resultValues.size());
|
||||||
|
|
||||||
resetter.reset();
|
resetter.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,6 +274,8 @@ public:
|
|||||||
typename... QueryTypes>
|
typename... QueryTypes>
|
||||||
Utils::optional<ResultType> value(const QueryTypes&... queryValues)
|
Utils::optional<ResultType> value(const QueryTypes&... queryValues)
|
||||||
{
|
{
|
||||||
|
BaseStatement::checkColumnCount(ResultTypeCount);
|
||||||
|
|
||||||
Resetter resetter{*this};
|
Resetter resetter{*this};
|
||||||
Utils::optional<ResultType> resultValue;
|
Utils::optional<ResultType> resultValue;
|
||||||
|
|
||||||
@@ -302,6 +294,8 @@ public:
|
|||||||
{
|
{
|
||||||
StatementImplementation statement(sqlStatement, database);
|
StatementImplementation statement(sqlStatement, database);
|
||||||
|
|
||||||
|
statement.checkColumnCount(1);
|
||||||
|
|
||||||
statement.next();
|
statement.next();
|
||||||
|
|
||||||
return statement.template fetchValue<Type>(0);
|
return statement.template fetchValue<Type>(0);
|
||||||
@@ -354,6 +348,7 @@ private:
|
|||||||
operator long long() { return statement.fetchLongLongValue(column); }
|
operator long long() { return statement.fetchLongLongValue(column); }
|
||||||
operator double() { return statement.fetchDoubleValue(column); }
|
operator double() { return statement.fetchDoubleValue(column); }
|
||||||
operator Utils::SmallStringView() { return statement.fetchSmallStringViewValue(column); }
|
operator Utils::SmallStringView() { return statement.fetchSmallStringViewValue(column); }
|
||||||
|
operator Utils::span<const Sqlite::byte>() { return statement.fetchBlobValue(column); }
|
||||||
operator ValueView() { return statement.fetchValueView(column); }
|
operator ValueView() { return statement.fetchValueView(column); }
|
||||||
|
|
||||||
StatementImplementation &statement;
|
StatementImplementation &statement;
|
||||||
@@ -401,19 +396,6 @@ private:
|
|||||||
bindValuesByIndex(index + 1, values...);
|
bindValuesByIndex(index + 1, values...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ValueType>
|
|
||||||
void bindValuesByName(Utils::SmallStringView name, const ValueType &value)
|
|
||||||
{
|
|
||||||
BaseStatement::bind(BaseStatement::bindingIndexForName(name), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ValueType, typename... ValueTypes>
|
|
||||||
void bindValuesByName(Utils::SmallStringView name, const ValueType &value, const ValueTypes&... values)
|
|
||||||
{
|
|
||||||
BaseStatement::bind(BaseStatement::bindingIndexForName(name), value);
|
|
||||||
bindValuesByName(values...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TupleType, std::size_t... ColumnIndices>
|
template <typename TupleType, std::size_t... ColumnIndices>
|
||||||
void bindTupleValuesElement(const TupleType &tuple, std::index_sequence<ColumnIndices...>)
|
void bindTupleValuesElement(const TupleType &tuple, std::index_sequence<ColumnIndices...>)
|
||||||
{
|
{
|
||||||
@@ -427,6 +409,13 @@ private:
|
|||||||
bindTupleValuesElement(element, ColumnIndices());
|
bindTupleValuesElement(element, ColumnIndices());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setMaximumResultCount(std::size_t count)
|
||||||
|
{
|
||||||
|
m_maximumResultCount = std::max(m_maximumResultCount, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::size_t m_maximumResultCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
@@ -25,72 +25,50 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sqliteglobal.h"
|
#include "constraints.h"
|
||||||
|
|
||||||
#include <utils/smallstring.h>
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
|
|
||||||
class Column
|
class Column
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Column() = default;
|
Column() = default;
|
||||||
|
|
||||||
Column(Utils::SmallString &&name,
|
Column(Utils::SmallStringView tableName,
|
||||||
ColumnType type = ColumnType::Numeric,
|
Utils::SmallStringView name,
|
||||||
Contraint constraint = Contraint::NoConstraint)
|
ColumnType type,
|
||||||
: m_name(std::move(name)),
|
Constraints &&constraints = {})
|
||||||
m_type(type),
|
: constraints(std::move(constraints))
|
||||||
m_constraint(constraint)
|
, name(name)
|
||||||
|
, tableName(tableName)
|
||||||
|
, type(type)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
m_name.clear();
|
name.clear();
|
||||||
m_type = ColumnType::Numeric;
|
type = ColumnType::Numeric;
|
||||||
m_constraint = Contraint::NoConstraint;
|
constraints = {};
|
||||||
}
|
|
||||||
|
|
||||||
void setName(Utils::SmallString &&newName)
|
|
||||||
{
|
|
||||||
m_name = newName;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Utils::SmallString &name() const
|
|
||||||
{
|
|
||||||
return m_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setType(ColumnType newType)
|
|
||||||
{
|
|
||||||
m_type = newType;
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnType type() const
|
|
||||||
{
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setContraint(Contraint constraint)
|
|
||||||
{
|
|
||||||
m_constraint = constraint;
|
|
||||||
}
|
|
||||||
|
|
||||||
Contraint constraint() const
|
|
||||||
{
|
|
||||||
return m_constraint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::SmallString typeString() const
|
Utils::SmallString typeString() const
|
||||||
{
|
{
|
||||||
switch (m_type) {
|
switch (type) {
|
||||||
case ColumnType::None: return {};
|
case ColumnType::None:
|
||||||
case ColumnType::Numeric: return "NUMERIC";
|
return {};
|
||||||
case ColumnType::Integer: return "INTEGER";
|
case ColumnType::Numeric:
|
||||||
case ColumnType::Real: return "REAL";
|
return "NUMERIC";
|
||||||
case ColumnType::Text: return "TEXT";
|
case ColumnType::Integer:
|
||||||
|
return "INTEGER";
|
||||||
|
case ColumnType::Real:
|
||||||
|
return "REAL";
|
||||||
|
case ColumnType::Text:
|
||||||
|
return "TEXT";
|
||||||
|
case ColumnType::Blob:
|
||||||
|
return "BLOB";
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
@@ -98,16 +76,16 @@ public:
|
|||||||
|
|
||||||
friend bool operator==(const Column &first, const Column &second)
|
friend bool operator==(const Column &first, const Column &second)
|
||||||
{
|
{
|
||||||
return first.m_name == second.m_name
|
return first.name == second.name && first.type == second.type
|
||||||
&& first.m_type == second.m_type
|
&& first.constraints == second.constraints && first.tableName == second.tableName;
|
||||||
&& first.m_constraint == second.m_constraint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
public:
|
||||||
Utils::SmallString m_name;
|
Constraints constraints;
|
||||||
ColumnType m_type = ColumnType::Numeric;
|
Utils::SmallString name;
|
||||||
Contraint m_constraint = Contraint::NoConstraint;
|
Utils::SmallString tableName;
|
||||||
};
|
ColumnType type = ColumnType::Numeric;
|
||||||
|
}; // namespace Sqlite
|
||||||
|
|
||||||
using SqliteColumns = std::vector<Column>;
|
using SqliteColumns = std::vector<Column>;
|
||||||
using SqliteColumnConstReference = std::reference_wrapper<const Column>;
|
using SqliteColumnConstReference = std::reference_wrapper<const Column>;
|
||||||
|
@@ -25,9 +25,10 @@
|
|||||||
|
|
||||||
#include "sqlitedatabase.h"
|
#include "sqlitedatabase.h"
|
||||||
|
|
||||||
|
#include "sqlitereadwritestatement.h"
|
||||||
|
#include "sqlitesessions.h"
|
||||||
#include "sqlitetable.h"
|
#include "sqlitetable.h"
|
||||||
#include "sqlitetransaction.h"
|
#include "sqlitetransaction.h"
|
||||||
#include "sqlitereadwritestatement.h"
|
|
||||||
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
@@ -51,6 +52,7 @@ public:
|
|||||||
ReadWriteStatement exclusiveBegin{"BEGIN EXCLUSIVE", database};
|
ReadWriteStatement exclusiveBegin{"BEGIN EXCLUSIVE", database};
|
||||||
ReadWriteStatement commitBegin{"COMMIT", database};
|
ReadWriteStatement commitBegin{"COMMIT", database};
|
||||||
ReadWriteStatement rollbackBegin{"ROLLBACK", database};
|
ReadWriteStatement rollbackBegin{"ROLLBACK", database};
|
||||||
|
Sessions sessions{database, "main", "databaseSessions"};
|
||||||
};
|
};
|
||||||
|
|
||||||
Database::Database()
|
Database::Database()
|
||||||
@@ -60,21 +62,29 @@ Database::Database()
|
|||||||
|
|
||||||
Database::Database(Utils::PathString &&databaseFilePath, JournalMode journalMode)
|
Database::Database(Utils::PathString &&databaseFilePath, JournalMode journalMode)
|
||||||
: Database(std::move(databaseFilePath), 1000ms, journalMode)
|
: Database(std::move(databaseFilePath), 1000ms, journalMode)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
Database::Database(Utils::PathString &&databaseFilePath,
|
Database::Database(Utils::PathString &&databaseFilePath,
|
||||||
std::chrono::milliseconds busyTimeout,
|
std::chrono::milliseconds busyTimeout,
|
||||||
JournalMode journalMode)
|
JournalMode journalMode)
|
||||||
: m_databaseBackend(*this),
|
: m_databaseBackend(*this)
|
||||||
m_busyTimeout(busyTimeout)
|
, m_busyTimeout(busyTimeout)
|
||||||
{
|
{
|
||||||
setJournalMode(journalMode);
|
setJournalMode(journalMode);
|
||||||
open(std::move(databaseFilePath));
|
open(std::move(databaseFilePath));
|
||||||
|
|
||||||
|
#ifndef QT_NO_DEBUG
|
||||||
|
execute("PRAGMA reverse_unordered_selects=1");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Database::~Database() = default;
|
Database::~Database() = default;
|
||||||
|
|
||||||
|
void Database::activateLogging()
|
||||||
|
{
|
||||||
|
DatabaseBackend::activateLogging();
|
||||||
|
}
|
||||||
|
|
||||||
void Database::open()
|
void Database::open()
|
||||||
{
|
{
|
||||||
m_databaseBackend.open(m_databaseFilePath, m_openMode);
|
m_databaseBackend.open(m_databaseFilePath, m_openMode);
|
||||||
@@ -131,6 +141,16 @@ void Database::setDatabaseFilePath(Utils::PathString &&databaseFilePath)
|
|||||||
m_databaseFilePath = std::move(databaseFilePath);
|
m_databaseFilePath = std::move(databaseFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Database::setAttachedTables(const Utils::SmallStringVector &tables)
|
||||||
|
{
|
||||||
|
m_statements->sessions.setAttachedTables(tables);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Database::applyAndUpdateSessions()
|
||||||
|
{
|
||||||
|
m_statements->sessions.applyAndUpdateSessions();
|
||||||
|
}
|
||||||
|
|
||||||
const Utils::PathString &Database::databaseFilePath() const
|
const Utils::PathString &Database::databaseFilePath() const
|
||||||
{
|
{
|
||||||
return m_databaseFilePath;
|
return m_databaseFilePath;
|
||||||
@@ -210,6 +230,22 @@ void Database::rollback()
|
|||||||
m_statements->rollbackBegin.execute();
|
m_statements->rollbackBegin.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Database::immediateSessionBegin()
|
||||||
|
{
|
||||||
|
m_statements->immediateBegin.execute();
|
||||||
|
m_statements->sessions.create();
|
||||||
|
}
|
||||||
|
void Database::sessionCommit()
|
||||||
|
{
|
||||||
|
m_statements->sessions.commit();
|
||||||
|
m_statements->commitBegin.execute();
|
||||||
|
}
|
||||||
|
void Database::sessionRollback()
|
||||||
|
{
|
||||||
|
m_statements->sessions.rollback();
|
||||||
|
m_statements->rollbackBegin.execute();
|
||||||
|
}
|
||||||
|
|
||||||
void Database::lock()
|
void Database::lock()
|
||||||
{
|
{
|
||||||
m_databaseMutex.lock();
|
m_databaseMutex.lock();
|
||||||
|
@@ -66,6 +66,8 @@ public:
|
|||||||
Database(const Database &) = delete;
|
Database(const Database &) = delete;
|
||||||
Database &operator=(const Database &) = delete;
|
Database &operator=(const Database &) = delete;
|
||||||
|
|
||||||
|
static void activateLogging();
|
||||||
|
|
||||||
void open();
|
void open();
|
||||||
void open(Utils::PathString &&databaseFilePath);
|
void open(Utils::PathString &&databaseFilePath);
|
||||||
void close();
|
void close();
|
||||||
@@ -108,7 +110,21 @@ public:
|
|||||||
|
|
||||||
int totalChangesCount() { return m_databaseBackend.totalChangesCount(); }
|
int totalChangesCount() { return m_databaseBackend.totalChangesCount(); }
|
||||||
|
|
||||||
void walCheckpointFull() override { m_databaseBackend.walCheckpointFull(); }
|
void walCheckpointFull() override
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock{m_databaseMutex};
|
||||||
|
m_databaseBackend.walCheckpointFull();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUpdateHook(DatabaseBackend::UpdateCallback &callback)
|
||||||
|
{
|
||||||
|
m_databaseBackend.setUpdateHook(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetUpdateHook() { m_databaseBackend.resetUpdateHook(); }
|
||||||
|
|
||||||
|
void setAttachedTables(const Utils::SmallStringVector &tables);
|
||||||
|
void applyAndUpdateSessions();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void deferredBegin() override;
|
void deferredBegin() override;
|
||||||
@@ -118,6 +134,9 @@ private:
|
|||||||
void rollback() override;
|
void rollback() override;
|
||||||
void lock() override;
|
void lock() override;
|
||||||
void unlock() override;
|
void unlock() override;
|
||||||
|
void immediateSessionBegin() override;
|
||||||
|
void sessionCommit() override;
|
||||||
|
void sessionRollback() override;
|
||||||
|
|
||||||
void initializeTables();
|
void initializeTables();
|
||||||
void registerTransactionStatements();
|
void registerTransactionStatements();
|
||||||
|
@@ -37,12 +37,15 @@
|
|||||||
|
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
int sqlite3_carray_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||||
|
}
|
||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
DatabaseBackend::DatabaseBackend(Database &database)
|
DatabaseBackend::DatabaseBackend(Database &database)
|
||||||
: m_database(database),
|
: m_database(database)
|
||||||
m_databaseHandle(nullptr),
|
, m_databaseHandle(nullptr)
|
||||||
m_cachedTextEncoding(Utf8)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,13 +68,15 @@ void DatabaseBackend::activateMultiThreading()
|
|||||||
|
|
||||||
static void sqliteLog(void*,int errorCode,const char *errorMessage)
|
static void sqliteLog(void*,int errorCode,const char *errorMessage)
|
||||||
{
|
{
|
||||||
qWarning() << sqlite3_errstr(errorCode) << errorMessage;
|
std::cout << "Sqlite " << sqlite3_errstr(errorCode) << ": " << errorMessage << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseBackend::activateLogging()
|
void DatabaseBackend::activateLogging()
|
||||||
{
|
{
|
||||||
|
if (qEnvironmentVariableIsSet("QTC_SQLITE_LOGGING")) {
|
||||||
int resultCode = sqlite3_config(SQLITE_CONFIG_LOG, sqliteLog, nullptr);
|
int resultCode = sqlite3_config(SQLITE_CONFIG_LOG, sqliteLog, nullptr);
|
||||||
checkIfLoogingIsActivated(resultCode);
|
checkIfLoogingIsActivated(resultCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseBackend::initializeSqliteLibrary()
|
void DatabaseBackend::initializeSqliteLibrary()
|
||||||
@@ -103,7 +108,9 @@ void DatabaseBackend::open(Utils::SmallStringView databaseFilePath, OpenMode mod
|
|||||||
|
|
||||||
checkDatabaseCouldBeOpened(resultCode);
|
checkDatabaseCouldBeOpened(resultCode);
|
||||||
|
|
||||||
cacheTextEncoding();
|
resultCode = sqlite3_carray_init(m_databaseHandle, nullptr, nullptr);
|
||||||
|
|
||||||
|
checkCarrayCannotBeIntialized(resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3 *DatabaseBackend::sqliteDatabaseHandle() const
|
sqlite3 *DatabaseBackend::sqliteDatabaseHandle() const
|
||||||
@@ -135,24 +142,6 @@ JournalMode DatabaseBackend::journalMode()
|
|||||||
return pragmaToJournalMode(pragmaValue("journal_mode"));
|
return pragmaToJournalMode(pragmaValue("journal_mode"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseBackend::setTextEncoding(TextEncoding textEncoding)
|
|
||||||
{
|
|
||||||
setPragmaValue("encoding", textEncodingToPragma(textEncoding));
|
|
||||||
cacheTextEncoding();
|
|
||||||
}
|
|
||||||
|
|
||||||
TextEncoding DatabaseBackend::textEncoding()
|
|
||||||
{
|
|
||||||
return m_cachedTextEncoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Utils::SmallStringVector DatabaseBackend::columnNames(Utils::SmallStringView tableName)
|
|
||||||
{
|
|
||||||
ReadWriteStatement statement("SELECT * FROM " + tableName, m_database);
|
|
||||||
return statement.columnNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatabaseBackend::changesCount() const
|
int DatabaseBackend::changesCount() const
|
||||||
{
|
{
|
||||||
return sqlite3_changes(sqliteDatabaseHandle());
|
return sqlite3_changes(sqliteDatabaseHandle());
|
||||||
@@ -232,11 +221,6 @@ int DatabaseBackend::busyHandlerCallback(void *, int counter)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseBackend::cacheTextEncoding()
|
|
||||||
{
|
|
||||||
m_cachedTextEncoding = pragmaToTextEncoding(pragmaValue("encoding"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DatabaseBackend::checkForOpenDatabaseWhichCanBeClosed()
|
void DatabaseBackend::checkForOpenDatabaseWhichCanBeClosed()
|
||||||
{
|
{
|
||||||
if (m_databaseHandle == nullptr)
|
if (m_databaseHandle == nullptr)
|
||||||
@@ -272,10 +256,19 @@ void DatabaseBackend::checkDatabaseCouldBeOpened(int resultCode)
|
|||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
closeWithoutException();
|
closeWithoutException();
|
||||||
throw Exception("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened:", sqlite3_errmsg(sqliteDatabaseHandle()));
|
throw Exception(
|
||||||
|
"SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened:",
|
||||||
|
sqlite3_errmsg(sqliteDatabaseHandle()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DatabaseBackend::checkCarrayCannotBeIntialized(int resultCode)
|
||||||
|
{
|
||||||
|
if (resultCode != SQLITE_OK)
|
||||||
|
throwDatabaseIsNotOpen(
|
||||||
|
"SqliteDatabaseBackend: database cannot be opened because carray failed!");
|
||||||
|
}
|
||||||
|
|
||||||
void DatabaseBackend::checkPragmaValue(Utils::SmallStringView databaseValue,
|
void DatabaseBackend::checkPragmaValue(Utils::SmallStringView databaseValue,
|
||||||
Utils::SmallStringView expectedValue)
|
Utils::SmallStringView expectedValue)
|
||||||
{
|
{
|
||||||
@@ -292,31 +285,35 @@ void DatabaseBackend::checkDatabaseHandleIsNotNull() const
|
|||||||
void DatabaseBackend::checkIfMultithreadingIsActivated(int resultCode)
|
void DatabaseBackend::checkIfMultithreadingIsActivated(int resultCode)
|
||||||
{
|
{
|
||||||
if (resultCode != SQLITE_OK)
|
if (resultCode != SQLITE_OK)
|
||||||
throwException("SqliteDatabaseBackend::activateMultiThreading: multithreading can't be activated!");
|
throwExceptionStatic(
|
||||||
|
"SqliteDatabaseBackend::activateMultiThreading: multithreading can't be activated!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseBackend::checkIfLoogingIsActivated(int resultCode)
|
void DatabaseBackend::checkIfLoogingIsActivated(int resultCode)
|
||||||
{
|
{
|
||||||
if (resultCode != SQLITE_OK)
|
if (resultCode != SQLITE_OK)
|
||||||
throwException("SqliteDatabaseBackend::activateLogging: logging can't be activated!");
|
throwExceptionStatic("SqliteDatabaseBackend::activateLogging: logging can't be activated!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseBackend::checkMmapSizeIsSet(int resultCode)
|
void DatabaseBackend::checkMmapSizeIsSet(int resultCode)
|
||||||
{
|
{
|
||||||
if (resultCode != SQLITE_OK)
|
if (resultCode != SQLITE_OK)
|
||||||
throwException("SqliteDatabaseBackend::checkMmapSizeIsSet: mmap size can't be changed!");
|
throwExceptionStatic(
|
||||||
|
"SqliteDatabaseBackend::checkMmapSizeIsSet: mmap size can't be changed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseBackend::checkInitializeSqliteLibraryWasSuccesful(int resultCode)
|
void DatabaseBackend::checkInitializeSqliteLibraryWasSuccesful(int resultCode)
|
||||||
{
|
{
|
||||||
if (resultCode != SQLITE_OK)
|
if (resultCode != SQLITE_OK)
|
||||||
throwException("SqliteDatabaseBackend::initializeSqliteLibrary: SqliteLibrary cannot initialized!");
|
throwExceptionStatic(
|
||||||
|
"SqliteDatabaseBackend::initializeSqliteLibrary: SqliteLibrary cannot initialized!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseBackend::checkShutdownSqliteLibraryWasSuccesful(int resultCode)
|
void DatabaseBackend::checkShutdownSqliteLibraryWasSuccesful(int resultCode)
|
||||||
{
|
{
|
||||||
if (resultCode != SQLITE_OK)
|
if (resultCode != SQLITE_OK)
|
||||||
throwException("SqliteDatabaseBackend::shutdownSqliteLibrary: SqliteLibrary cannot be shutdowned!");
|
throwExceptionStatic(
|
||||||
|
"SqliteDatabaseBackend::shutdownSqliteLibrary: SqliteLibrary cannot be shutdowned!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseBackend::checkIfLogCouldBeCheckpointed(int resultCode)
|
void DatabaseBackend::checkIfLogCouldBeCheckpointed(int resultCode)
|
||||||
@@ -344,13 +341,11 @@ int indexOfPragma(Utils::SmallStringView pragma, const Utils::SmallStringView (&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const Utils::SmallStringView journalModeStrings[] = {
|
const Utils::SmallStringView journalModeStrings[] = {"delete",
|
||||||
"delete",
|
|
||||||
"truncate",
|
"truncate",
|
||||||
"persist",
|
"persist",
|
||||||
"memory",
|
"memory",
|
||||||
"wal"
|
"wal"};
|
||||||
};
|
|
||||||
|
|
||||||
Utils::SmallStringView DatabaseBackend::journalModeToPragma(JournalMode journalMode)
|
Utils::SmallStringView DatabaseBackend::journalModeToPragma(JournalMode journalMode)
|
||||||
{
|
{
|
||||||
@@ -367,27 +362,6 @@ JournalMode DatabaseBackend::pragmaToJournalMode(Utils::SmallStringView pragma)
|
|||||||
return static_cast<JournalMode>(index);
|
return static_cast<JournalMode>(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const Utils::SmallStringView textEncodingStrings[] = {
|
|
||||||
"UTF-8",
|
|
||||||
"UTF-16le",
|
|
||||||
"UTF-16be"
|
|
||||||
};
|
|
||||||
|
|
||||||
Utils::SmallStringView DatabaseBackend::textEncodingToPragma(TextEncoding textEncoding)
|
|
||||||
{
|
|
||||||
return textEncodingStrings[textEncoding];
|
|
||||||
}
|
|
||||||
|
|
||||||
TextEncoding DatabaseBackend::pragmaToTextEncoding(Utils::SmallStringView pragma)
|
|
||||||
{
|
|
||||||
int index = indexOfPragma(pragma, textEncodingStrings);
|
|
||||||
|
|
||||||
if (index < 0)
|
|
||||||
throwExceptionStatic("SqliteDatabaseBackend::pragmaToTextEncoding: pragma can't be transformed in a text encoding enumeration!");
|
|
||||||
|
|
||||||
return static_cast<TextEncoding>(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatabaseBackend::openMode(OpenMode mode)
|
int DatabaseBackend::openMode(OpenMode mode)
|
||||||
{
|
{
|
||||||
int sqliteMode = SQLITE_OPEN_CREATE;
|
int sqliteMode = SQLITE_OPEN_CREATE;
|
||||||
@@ -426,6 +400,29 @@ void DatabaseBackend::walCheckpointFull()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void updateCallback(
|
||||||
|
void *callback, int type, char const *database, char const *table, sqlite3_int64 row)
|
||||||
|
{
|
||||||
|
auto &function = *reinterpret_cast<DatabaseBackend::UpdateCallback *>(callback);
|
||||||
|
|
||||||
|
function(static_cast<ChangeType>(type), database, table, row);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void DatabaseBackend::setUpdateHook(UpdateCallback &callback)
|
||||||
|
{
|
||||||
|
if (callback)
|
||||||
|
sqlite3_update_hook(m_databaseHandle, updateCallback, &callback);
|
||||||
|
else
|
||||||
|
sqlite3_update_hook(m_databaseHandle, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseBackend::resetUpdateHook()
|
||||||
|
{
|
||||||
|
sqlite3_update_hook(m_databaseHandle, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
void DatabaseBackend::throwExceptionStatic(const char *whatHasHappens)
|
void DatabaseBackend::throwExceptionStatic(const char *whatHasHappens)
|
||||||
{
|
{
|
||||||
throw Exception(whatHasHappens);
|
throw Exception(whatHasHappens);
|
||||||
|
@@ -40,6 +40,9 @@ class Database;
|
|||||||
class SQLITE_EXPORT DatabaseBackend
|
class SQLITE_EXPORT DatabaseBackend
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using UpdateCallback
|
||||||
|
= std::function<void(ChangeType type, char const *, char const *, long long)>;
|
||||||
|
|
||||||
DatabaseBackend(Database &database);
|
DatabaseBackend(Database &database);
|
||||||
~DatabaseBackend();
|
~DatabaseBackend();
|
||||||
|
|
||||||
@@ -49,11 +52,11 @@ public:
|
|||||||
DatabaseBackend(DatabaseBackend &&) = delete;
|
DatabaseBackend(DatabaseBackend &&) = delete;
|
||||||
DatabaseBackend &operator=(DatabaseBackend &&) = delete;
|
DatabaseBackend &operator=(DatabaseBackend &&) = delete;
|
||||||
|
|
||||||
void setMmapSize(qint64 defaultSize, qint64 maximumSize);
|
static void setMmapSize(qint64 defaultSize, qint64 maximumSize);
|
||||||
void activateMultiThreading();
|
static void activateMultiThreading();
|
||||||
void activateLogging();
|
static void activateLogging();
|
||||||
void initializeSqliteLibrary();
|
static void initializeSqliteLibrary();
|
||||||
void shutdownSqliteLibrary();
|
static void shutdownSqliteLibrary();
|
||||||
void checkpointFullWalLog();
|
void checkpointFullWalLog();
|
||||||
|
|
||||||
void open(Utils::SmallStringView databaseFilePath, OpenMode openMode);
|
void open(Utils::SmallStringView databaseFilePath, OpenMode openMode);
|
||||||
@@ -65,9 +68,6 @@ public:
|
|||||||
void setJournalMode(JournalMode journalMode);
|
void setJournalMode(JournalMode journalMode);
|
||||||
JournalMode journalMode();
|
JournalMode journalMode();
|
||||||
|
|
||||||
void setTextEncoding(TextEncoding textEncoding);
|
|
||||||
TextEncoding textEncoding();
|
|
||||||
|
|
||||||
Utils::SmallStringVector columnNames(Utils::SmallStringView tableName);
|
Utils::SmallStringVector columnNames(Utils::SmallStringView tableName);
|
||||||
|
|
||||||
int changesCount() const;
|
int changesCount() const;
|
||||||
@@ -87,6 +87,9 @@ public:
|
|||||||
|
|
||||||
void walCheckpointFull();
|
void walCheckpointFull();
|
||||||
|
|
||||||
|
void setUpdateHook(UpdateCallback &callback);
|
||||||
|
void resetUpdateHook();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool databaseIsOpen() const;
|
bool databaseIsOpen() const;
|
||||||
|
|
||||||
@@ -97,27 +100,23 @@ protected:
|
|||||||
void registerRankingFunction();
|
void registerRankingFunction();
|
||||||
static int busyHandlerCallback(void*, int counter);
|
static int busyHandlerCallback(void*, int counter);
|
||||||
|
|
||||||
void cacheTextEncoding();
|
|
||||||
|
|
||||||
void checkForOpenDatabaseWhichCanBeClosed();
|
void checkForOpenDatabaseWhichCanBeClosed();
|
||||||
void checkDatabaseClosing(int resultCode);
|
void checkDatabaseClosing(int resultCode);
|
||||||
void checkCanOpenDatabase(Utils::SmallStringView databaseFilePath);
|
void checkCanOpenDatabase(Utils::SmallStringView databaseFilePath);
|
||||||
void checkDatabaseCouldBeOpened(int resultCode);
|
void checkDatabaseCouldBeOpened(int resultCode);
|
||||||
|
void checkCarrayCannotBeIntialized(int resultCode);
|
||||||
void checkPragmaValue(Utils::SmallStringView databaseValue, Utils::SmallStringView expectedValue);
|
void checkPragmaValue(Utils::SmallStringView databaseValue, Utils::SmallStringView expectedValue);
|
||||||
void checkDatabaseHandleIsNotNull() const;
|
void checkDatabaseHandleIsNotNull() const;
|
||||||
void checkIfMultithreadingIsActivated(int resultCode);
|
static void checkIfMultithreadingIsActivated(int resultCode);
|
||||||
void checkIfLoogingIsActivated(int resultCode);
|
static void checkIfLoogingIsActivated(int resultCode);
|
||||||
void checkMmapSizeIsSet(int resultCode);
|
static void checkMmapSizeIsSet(int resultCode);
|
||||||
void checkInitializeSqliteLibraryWasSuccesful(int resultCode);
|
static void checkInitializeSqliteLibraryWasSuccesful(int resultCode);
|
||||||
void checkShutdownSqliteLibraryWasSuccesful(int resultCode);
|
static void checkShutdownSqliteLibraryWasSuccesful(int resultCode);
|
||||||
void checkIfLogCouldBeCheckpointed(int resultCode);
|
void checkIfLogCouldBeCheckpointed(int resultCode);
|
||||||
void checkIfBusyTimeoutWasSet(int resultCode);
|
void checkIfBusyTimeoutWasSet(int resultCode);
|
||||||
|
|
||||||
static Utils::SmallStringView journalModeToPragma(JournalMode journalMode);
|
static Utils::SmallStringView journalModeToPragma(JournalMode journalMode);
|
||||||
static JournalMode pragmaToJournalMode(Utils::SmallStringView pragma);
|
static JournalMode pragmaToJournalMode(Utils::SmallStringView pragma);
|
||||||
Utils::SmallStringView textEncodingToPragma(TextEncoding textEncoding);
|
|
||||||
static TextEncoding pragmaToTextEncoding(Utils::SmallStringView pragma);
|
|
||||||
|
|
||||||
|
|
||||||
Q_NORETURN static void throwExceptionStatic(const char *whatHasHappens);
|
Q_NORETURN static void throwExceptionStatic(const char *whatHasHappens);
|
||||||
[[noreturn]] void throwException(const char *whatHasHappens) const;
|
[[noreturn]] void throwException(const char *whatHasHappens) const;
|
||||||
@@ -127,8 +126,6 @@ protected:
|
|||||||
private:
|
private:
|
||||||
Database &m_database;
|
Database &m_database;
|
||||||
sqlite3 *m_databaseHandle;
|
sqlite3 *m_databaseHandle;
|
||||||
TextEncoding m_cachedTextEncoding;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
@@ -25,11 +25,25 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/smallstringvector.h>
|
||||||
|
|
||||||
|
#include "sqliteglobal.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
class DatabaseInterface
|
class DatabaseInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using UpdateCallback
|
||||||
|
= std::function<void(ChangeType type, char const *, char const *, long long)>;
|
||||||
|
|
||||||
virtual void walCheckpointFull() = 0;
|
virtual void walCheckpointFull() = 0;
|
||||||
|
virtual void execute(Utils::SmallStringView sqlStatement) = 0;
|
||||||
|
virtual void setUpdateHook(UpdateCallback &callback) = 0;
|
||||||
|
virtual void resetUpdateHook() = 0;
|
||||||
|
virtual void applyAndUpdateSessions() = 0;
|
||||||
|
virtual void setAttachedTables(const Utils::SmallStringVector &tables) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~DatabaseInterface() = default;
|
~DatabaseInterface() = default;
|
||||||
|
@@ -29,17 +29,21 @@
|
|||||||
|
|
||||||
#include <utils/smallstring.h>
|
#include <utils/smallstring.h>
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
class SQLITE_EXPORT Exception
|
class SQLITE_EXPORT Exception : public std::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Exception(const char *whatErrorHasHappen,
|
Exception(const char *whatErrorHasHappen,
|
||||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||||
: m_whatErrorHasHappen(whatErrorHasHappen),
|
: m_whatErrorHasHappen(whatErrorHasHappen)
|
||||||
m_sqliteErrorMessage(std::move(sqliteErrorMessage))
|
, m_sqliteErrorMessage(std::move(sqliteErrorMessage))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
const char *what() const noexcept override { return m_whatErrorHasHappen; }
|
||||||
|
|
||||||
void printWarning() const;
|
void printWarning() const;
|
||||||
|
|
||||||
@@ -115,13 +119,12 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class InvalidColumnFetched : public Exception
|
class ColumnCountDoesNotMatch : public Exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InvalidColumnFetched(const char *whatErrorHasHappen)
|
ColumnCountDoesNotMatch(const char *whatErrorHasHappen)
|
||||||
: Exception(whatErrorHasHappen)
|
: Exception(whatErrorHasHappen)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BindingIndexIsOutOfRange : public Exception
|
class BindingIndexIsOutOfRange : public Exception
|
||||||
@@ -272,4 +275,28 @@ public:
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ForeignKeyColumnIsNotUnique : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ForeignKeyColumnIsNotUnique(const char *whatErrorHasHappen)
|
||||||
|
: Exception(whatErrorHasHappen)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CannotApplyChangeSet : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CannotApplyChangeSet(const char *whatErrorHasHappen)
|
||||||
|
: Exception(whatErrorHasHappen)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChangeSetIsMisused : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ChangeSetIsMisused(const char *whatErrorHasHappen)
|
||||||
|
: Exception(whatErrorHasHappen)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
@@ -39,26 +39,15 @@
|
|||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
enum class ColumnType : char
|
enum class ColumnType : char { Numeric, Integer, Real, Text, Blob, None };
|
||||||
{
|
|
||||||
Numeric,
|
|
||||||
Integer,
|
|
||||||
Real,
|
|
||||||
Text,
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Contraint : char
|
enum class ConstraintType : char { NoConstraint, PrimaryKey, Unique, ForeignKey };
|
||||||
{
|
|
||||||
NoConstraint,
|
|
||||||
PrimaryKey,
|
|
||||||
Unique
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ColumnConstraint : char
|
enum class ForeignKeyAction : char { NoAction, Restrict, SetNull, SetDefault, Cascade };
|
||||||
{
|
|
||||||
PrimaryKey
|
enum class Enforment : char { Immediate, Deferred };
|
||||||
};
|
|
||||||
|
enum class ColumnConstraint : char { PrimaryKey };
|
||||||
|
|
||||||
enum class JournalMode : char
|
enum class JournalMode : char
|
||||||
{
|
{
|
||||||
@@ -75,17 +64,8 @@ enum class OpenMode : char
|
|||||||
ReadWrite
|
ReadWrite
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TextEncoding : char
|
enum class ChangeType : int { Delete = 9, Insert = 18, Update = 23 };
|
||||||
{
|
|
||||||
Utf8,
|
|
||||||
Utf16le,
|
|
||||||
Utf16be,
|
|
||||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
|
||||||
Utf16 = Utf16le
|
|
||||||
#else
|
|
||||||
Utf16 = Utf16be
|
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
enum class byte : unsigned char {};
|
||||||
|
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
@@ -41,7 +41,6 @@ public:
|
|||||||
using StatementImplementation::values;
|
using StatementImplementation::values;
|
||||||
using StatementImplementation::toValue;
|
using StatementImplementation::toValue;
|
||||||
using StatementImplementation::write;
|
using StatementImplementation::write;
|
||||||
using StatementImplementation::writeNamed;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
72
src/libs/sqlite/sqlitesessionchangeset.cpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "sqlitesessionchangeset.h"
|
||||||
|
#include "sqlitesessions.h"
|
||||||
|
|
||||||
|
#include <utils/smallstringio.h>
|
||||||
|
|
||||||
|
#include <sqlite3ext.h>
|
||||||
|
|
||||||
|
namespace Sqlite {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void checkResultCode(int resultCode)
|
||||||
|
{
|
||||||
|
switch (resultCode) {
|
||||||
|
case SQLITE_NOMEM:
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultCode != SQLITE_OK)
|
||||||
|
throw UnknowError("Unknow exception");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
SessionChangeSet::SessionChangeSet(Utils::span<const byte> blob)
|
||||||
|
: data(sqlite3_malloc64(blob.size()))
|
||||||
|
, size(int(blob.size()))
|
||||||
|
{
|
||||||
|
std::memcpy(data, blob.data(), blob.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionChangeSet::SessionChangeSet(Sessions &session)
|
||||||
|
{
|
||||||
|
int resultCode = sqlite3session_changeset(session.session.get(), &size, &data);
|
||||||
|
checkResultCode(resultCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionChangeSet::~SessionChangeSet()
|
||||||
|
{
|
||||||
|
sqlite3_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::span<const byte> SessionChangeSet::asSpan() const
|
||||||
|
{
|
||||||
|
return {static_cast<const byte *>(data), static_cast<std::size_t>(size)};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Sqlite
|
80
src/libs/sqlite/sqlitesessionchangeset.h
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sqliteglobal.h"
|
||||||
|
|
||||||
|
#include <utils/span.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
namespace Sqlite {
|
||||||
|
|
||||||
|
class Sessions;
|
||||||
|
|
||||||
|
class SessionChangeSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SessionChangeSet(Utils::span<const byte> blob);
|
||||||
|
SessionChangeSet(Sessions &session);
|
||||||
|
~SessionChangeSet();
|
||||||
|
SessionChangeSet(const SessionChangeSet &) = delete;
|
||||||
|
void operator=(const SessionChangeSet &) = delete;
|
||||||
|
SessionChangeSet(SessionChangeSet &&other) noexcept
|
||||||
|
{
|
||||||
|
SessionChangeSet temp;
|
||||||
|
swap(temp, other);
|
||||||
|
swap(temp, *this);
|
||||||
|
}
|
||||||
|
void operator=(SessionChangeSet &);
|
||||||
|
|
||||||
|
Utils::span<const byte> asSpan() const;
|
||||||
|
|
||||||
|
friend void swap(SessionChangeSet &first, SessionChangeSet &second) noexcept
|
||||||
|
{
|
||||||
|
SessionChangeSet temp;
|
||||||
|
std::swap(temp.data, first.data);
|
||||||
|
std::swap(temp.size, first.size);
|
||||||
|
std::swap(first.data, second.data);
|
||||||
|
std::swap(first.size, second.size);
|
||||||
|
std::swap(temp.data, second.data);
|
||||||
|
std::swap(temp.size, second.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SessionChangeSet() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void *data = nullptr;
|
||||||
|
int size = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
using SessionChangeSets = std::vector<SessionChangeSet>;
|
||||||
|
|
||||||
|
} // namespace Sqlite
|
188
src/libs/sqlite/sqlitesessions.cpp
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "sqlitesessions.h"
|
||||||
|
#include "sqlitereadstatement.h"
|
||||||
|
#include "sqlitesessionchangeset.h"
|
||||||
|
#include "sqlitetable.h"
|
||||||
|
|
||||||
|
#include <sqlite3ext.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace Sqlite {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void checkResultCode(int resultCode)
|
||||||
|
{
|
||||||
|
switch (resultCode) {
|
||||||
|
case SQLITE_NOMEM:
|
||||||
|
throw std::bad_alloc();
|
||||||
|
case SQLITE_SCHEMA:
|
||||||
|
throw CannotApplyChangeSet("Cannot apply change set!");
|
||||||
|
case SQLITE_MISUSE:
|
||||||
|
throw ChangeSetIsMisused("Change set is misused!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultCode != SQLITE_OK)
|
||||||
|
throw UnknowError("Unknow exception");
|
||||||
|
}
|
||||||
|
|
||||||
|
int xConflict(void *, int conflict, sqlite3_changeset_iter *)
|
||||||
|
{
|
||||||
|
switch (conflict) {
|
||||||
|
case SQLITE_CHANGESET_DATA:
|
||||||
|
return SQLITE_CHANGESET_REPLACE;
|
||||||
|
case SQLITE_CHANGESET_NOTFOUND:
|
||||||
|
return SQLITE_CHANGESET_OMIT;
|
||||||
|
case SQLITE_CHANGESET_CONFLICT:
|
||||||
|
return SQLITE_CHANGESET_REPLACE;
|
||||||
|
case SQLITE_CHANGESET_CONSTRAINT:
|
||||||
|
return SQLITE_CHANGESET_OMIT;
|
||||||
|
case SQLITE_CHANGESET_FOREIGN_KEY:
|
||||||
|
return SQLITE_CHANGESET_OMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SQLITE_CHANGESET_ABORT;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void Sessions::attachTables(const Utils::SmallStringVector &tableNames)
|
||||||
|
{
|
||||||
|
for (Utils::SmallStringView tableName : tableNames) {
|
||||||
|
int resultCode = sqlite3session_attach(session.get(), tableName.data());
|
||||||
|
checkResultCode(resultCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Sessions::~Sessions() = default;
|
||||||
|
|
||||||
|
void Sessions::setAttachedTables(Utils::SmallStringVector tables)
|
||||||
|
{
|
||||||
|
tableNames = std::move(tables);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sessions::create()
|
||||||
|
{
|
||||||
|
sqlite3_session *newSession = nullptr;
|
||||||
|
int resultCode = sqlite3session_create(database.backend().sqliteDatabaseHandle(),
|
||||||
|
databaseName.data(),
|
||||||
|
&newSession);
|
||||||
|
session.reset(newSession);
|
||||||
|
|
||||||
|
checkResultCode(resultCode);
|
||||||
|
|
||||||
|
attachTables(tableNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sessions::commit()
|
||||||
|
{
|
||||||
|
if (session && !sqlite3session_isempty(session.get())) {
|
||||||
|
SessionChangeSet changeSet{*this};
|
||||||
|
|
||||||
|
insertSession.write(changeSet.asSpan());
|
||||||
|
}
|
||||||
|
|
||||||
|
session.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sessions::rollback()
|
||||||
|
{
|
||||||
|
session.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Internal::SessionsBase::createSessionTable(Database &database)
|
||||||
|
{
|
||||||
|
Sqlite::Table table;
|
||||||
|
table.setUseIfNotExists(true);
|
||||||
|
table.setName(sessionsTableName);
|
||||||
|
table.addColumn("id", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{AutoIncrement::Yes}});
|
||||||
|
table.addColumn("changeset", Sqlite::ColumnType::Blob);
|
||||||
|
|
||||||
|
table.initialize(database);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sessions::revert()
|
||||||
|
{
|
||||||
|
ReadStatement selectChangeSets{Utils::PathString{"SELECT changeset FROM ",
|
||||||
|
sessionsTableName,
|
||||||
|
" ORDER BY id DESC"},
|
||||||
|
database};
|
||||||
|
|
||||||
|
auto changeSets = selectChangeSets.values<SessionChangeSet>(1024);
|
||||||
|
|
||||||
|
for (auto &changeSet : changeSets) {
|
||||||
|
int resultCode = sqlite3changeset_apply_v2(database.backend().sqliteDatabaseHandle(),
|
||||||
|
changeSet.size,
|
||||||
|
changeSet.data,
|
||||||
|
nullptr,
|
||||||
|
xConflict,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
SQLITE_CHANGESETAPPLY_INVERT
|
||||||
|
| SQLITE_CHANGESETAPPLY_NOSAVEPOINT);
|
||||||
|
checkResultCode(resultCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sessions::apply()
|
||||||
|
{
|
||||||
|
ReadStatement selectChangeSets{Utils::PathString{"SELECT changeset FROM ",
|
||||||
|
sessionsTableName,
|
||||||
|
" ORDER BY id"},
|
||||||
|
database};
|
||||||
|
|
||||||
|
auto changeSets = selectChangeSets.values<SessionChangeSet>(1024);
|
||||||
|
|
||||||
|
for (auto &changeSet : changeSets) {
|
||||||
|
int resultCode = sqlite3changeset_apply_v2(database.backend().sqliteDatabaseHandle(),
|
||||||
|
changeSet.size,
|
||||||
|
changeSet.data,
|
||||||
|
nullptr,
|
||||||
|
xConflict,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
SQLITE_CHANGESETAPPLY_NOSAVEPOINT);
|
||||||
|
checkResultCode(resultCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sessions::applyAndUpdateSessions()
|
||||||
|
{
|
||||||
|
create();
|
||||||
|
apply();
|
||||||
|
deleteAll();
|
||||||
|
commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sessions::deleteAll()
|
||||||
|
{
|
||||||
|
WriteStatement{Utils::SmallString{"DELETE FROM ", sessionsTableName}, database}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Sqlite
|
95
src/libs/sqlite/sqlitesessions.h
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sqlitedatabase.h"
|
||||||
|
#include "sqlitewritestatement.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
typedef struct sqlite3_session sqlite3_session;
|
||||||
|
void sqlite3session_delete(sqlite3_session *pSession);
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Sqlite {
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class SQLITE_EXPORT SessionsBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SessionsBase(Database &database, Utils::SmallStringView sessionsTableName)
|
||||||
|
: sessionsTableName(sessionsTableName)
|
||||||
|
{
|
||||||
|
createSessionTable(database);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createSessionTable(Database &database);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Utils::SmallString sessionsTableName;
|
||||||
|
};
|
||||||
|
} // namespace Internal
|
||||||
|
|
||||||
|
class SQLITE_EXPORT Sessions : public Internal::SessionsBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sessions(Database &database,
|
||||||
|
Utils::SmallStringView databaseName,
|
||||||
|
Utils::SmallStringView sessionsTableName)
|
||||||
|
: SessionsBase(database, sessionsTableName)
|
||||||
|
, database(database)
|
||||||
|
, insertSession{Utils::PathString{"INSERT INTO ",
|
||||||
|
sessionsTableName,
|
||||||
|
"(changeset) VALUES(?)"},
|
||||||
|
database}
|
||||||
|
, databaseName(databaseName)
|
||||||
|
, session{nullptr, sqlite3session_delete}
|
||||||
|
{}
|
||||||
|
~Sessions();
|
||||||
|
|
||||||
|
void setAttachedTables(Utils::SmallStringVector tables);
|
||||||
|
|
||||||
|
void create();
|
||||||
|
void commit();
|
||||||
|
void rollback();
|
||||||
|
|
||||||
|
void revert();
|
||||||
|
void apply();
|
||||||
|
void applyAndUpdateSessions();
|
||||||
|
void deleteAll();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void attachTables(const Utils::SmallStringVector &tables);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Database &database;
|
||||||
|
WriteStatement insertSession;
|
||||||
|
Utils::SmallString databaseName;
|
||||||
|
Utils::SmallStringVector tableNames;
|
||||||
|
std::unique_ptr<sqlite3_session, decltype(&sqlite3session_delete)> session;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Sqlite
|
@@ -44,10 +44,7 @@ public:
|
|||||||
m_sqliteIndices.reserve(reserve);
|
m_sqliteIndices.reserve(reserve);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setName(Utils::SmallString &&name)
|
void setName(Utils::SmallStringView name) { m_tableName = name; }
|
||||||
{
|
|
||||||
m_tableName = std::move(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils::SmallStringView name() const
|
Utils::SmallStringView name() const
|
||||||
{
|
{
|
||||||
@@ -74,15 +71,69 @@ public:
|
|||||||
m_useTemporaryTable = useTemporaryTable;
|
m_useTemporaryTable = useTemporaryTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
Column &addColumn(Utils::SmallString &&name,
|
Column &addColumn(Utils::SmallStringView name,
|
||||||
ColumnType type = ColumnType::Numeric,
|
ColumnType type = ColumnType::Numeric,
|
||||||
Contraint constraint = Contraint::NoConstraint)
|
Constraints &&constraints = {})
|
||||||
{
|
{
|
||||||
m_sqliteColumns.emplace_back(std::move(name), type, constraint);
|
m_sqliteColumns.emplace_back(m_tableName, name, type, std::move(constraints));
|
||||||
|
|
||||||
return m_sqliteColumns.back();
|
return m_sqliteColumns.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Column &addForeignKeyColumn(Utils::SmallStringView name,
|
||||||
|
const Table &referencedTable,
|
||||||
|
ForeignKeyAction foreignKeyupdateAction = {},
|
||||||
|
ForeignKeyAction foreignKeyDeleteAction = {},
|
||||||
|
Enforment foreignKeyEnforcement = {},
|
||||||
|
Constraints &&constraints = {},
|
||||||
|
ColumnType type = ColumnType::Integer)
|
||||||
|
{
|
||||||
|
constraints.emplace_back(ForeignKey{referencedTable.name(),
|
||||||
|
"",
|
||||||
|
foreignKeyupdateAction,
|
||||||
|
foreignKeyDeleteAction,
|
||||||
|
foreignKeyEnforcement});
|
||||||
|
|
||||||
|
m_sqliteColumns.emplace_back(m_tableName, name, type, std::move(constraints));
|
||||||
|
|
||||||
|
return m_sqliteColumns.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
Column &addForeignKeyColumn(Utils::SmallStringView name,
|
||||||
|
const Column &referencedColumn,
|
||||||
|
ForeignKeyAction foreignKeyupdateAction = {},
|
||||||
|
ForeignKeyAction foreignKeyDeleteAction = {},
|
||||||
|
Enforment foreignKeyEnforcement = {},
|
||||||
|
Constraints &&constraints = {})
|
||||||
|
{
|
||||||
|
if (!constainsUniqueIndex(referencedColumn.constraints))
|
||||||
|
throw ForeignKeyColumnIsNotUnique("Foreign column key must be unique!");
|
||||||
|
|
||||||
|
constraints.emplace_back(ForeignKey{referencedColumn.tableName,
|
||||||
|
referencedColumn.name,
|
||||||
|
foreignKeyupdateAction,
|
||||||
|
foreignKeyDeleteAction,
|
||||||
|
foreignKeyEnforcement});
|
||||||
|
|
||||||
|
m_sqliteColumns.emplace_back(m_tableName,
|
||||||
|
name,
|
||||||
|
referencedColumn.type,
|
||||||
|
std::move(constraints));
|
||||||
|
|
||||||
|
return m_sqliteColumns.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addPrimaryKeyContraint(const SqliteColumnConstReferences &columns)
|
||||||
|
{
|
||||||
|
Utils::SmallStringVector columnNames;
|
||||||
|
columnNames.reserve(columns.size());
|
||||||
|
|
||||||
|
for (const auto &column : columns)
|
||||||
|
columnNames.emplace_back(column.get().name);
|
||||||
|
|
||||||
|
m_tableConstraints.emplace_back(TablePrimaryKey{std::move(columnNames)});
|
||||||
|
}
|
||||||
|
|
||||||
Index &addIndex(const SqliteColumnConstReferences &columns)
|
Index &addIndex(const SqliteColumnConstReferences &columns)
|
||||||
{
|
{
|
||||||
m_sqliteIndices.emplace_back(m_tableName.clone(), sqliteColumnNames(columns));
|
m_sqliteIndices.emplace_back(m_tableName.clone(), sqliteColumnNames(columns));
|
||||||
@@ -119,6 +170,7 @@ public:
|
|||||||
builder.setUseIfNotExists(m_useIfNotExists);
|
builder.setUseIfNotExists(m_useIfNotExists);
|
||||||
builder.setUseTemporaryTable(m_useTemporaryTable);
|
builder.setUseTemporaryTable(m_useTemporaryTable);
|
||||||
builder.setColumns(m_sqliteColumns);
|
builder.setColumns(m_sqliteColumns);
|
||||||
|
builder.setConstraints(m_tableConstraints);
|
||||||
|
|
||||||
database.execute(builder.sqlStatement());
|
database.execute(builder.sqlStatement());
|
||||||
|
|
||||||
@@ -142,13 +194,23 @@ public:
|
|||||||
&& first.m_sqliteColumns == second.m_sqliteColumns;
|
&& first.m_sqliteColumns == second.m_sqliteColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool constainsUniqueIndex(const Constraints &constraints)
|
||||||
|
{
|
||||||
|
return std::find_if(constraints.begin(),
|
||||||
|
constraints.end(),
|
||||||
|
[](const Constraint &constraint) {
|
||||||
|
return Utils::holds_alternative<Unique>(constraint);
|
||||||
|
})
|
||||||
|
!= constraints.end();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Utils::SmallStringVector sqliteColumnNames(const SqliteColumnConstReferences &columns)
|
Utils::SmallStringVector sqliteColumnNames(const SqliteColumnConstReferences &columns)
|
||||||
{
|
{
|
||||||
Utils::SmallStringVector columnNames;
|
Utils::SmallStringVector columnNames;
|
||||||
|
|
||||||
for (const Column &column : columns)
|
for (const Column &column : columns)
|
||||||
columnNames.push_back(column.name());
|
columnNames.push_back(column.name);
|
||||||
|
|
||||||
return columnNames;
|
return columnNames;
|
||||||
}
|
}
|
||||||
@@ -157,6 +219,7 @@ private:
|
|||||||
Utils::SmallString m_tableName;
|
Utils::SmallString m_tableName;
|
||||||
SqliteColumns m_sqliteColumns;
|
SqliteColumns m_sqliteColumns;
|
||||||
SqliteIndices m_sqliteIndices;
|
SqliteIndices m_sqliteIndices;
|
||||||
|
TableConstraints m_tableConstraints;
|
||||||
bool m_withoutRowId = false;
|
bool m_withoutRowId = false;
|
||||||
bool m_useIfNotExists = false;
|
bool m_useIfNotExists = false;
|
||||||
bool m_useTemporaryTable = false;
|
bool m_useTemporaryTable = false;
|
||||||
|
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include "sqliteglobal.h"
|
#include "sqliteglobal.h"
|
||||||
|
|
||||||
|
#include <utils/smallstringview.h>
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
@@ -49,6 +51,9 @@ public:
|
|||||||
virtual void rollback() = 0;
|
virtual void rollback() = 0;
|
||||||
virtual void lock() = 0;
|
virtual void lock() = 0;
|
||||||
virtual void unlock() = 0;
|
virtual void unlock() = 0;
|
||||||
|
virtual void immediateSessionBegin() = 0;
|
||||||
|
virtual void sessionCommit() = 0;
|
||||||
|
virtual void sessionRollback() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~TransactionInterface() = default;
|
~TransactionInterface() = default;
|
||||||
@@ -82,6 +87,42 @@ protected:
|
|||||||
bool m_rollback = false;
|
bool m_rollback = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AbstractThrowingSessionTransaction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AbstractThrowingSessionTransaction(const AbstractTransaction &) = delete;
|
||||||
|
AbstractThrowingSessionTransaction &operator=(const AbstractTransaction &) = delete;
|
||||||
|
|
||||||
|
void commit()
|
||||||
|
{
|
||||||
|
m_interface.sessionCommit();
|
||||||
|
m_isAlreadyCommited = true;
|
||||||
|
m_locker.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
~AbstractThrowingSessionTransaction() noexcept(false)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (m_rollback)
|
||||||
|
m_interface.sessionRollback();
|
||||||
|
} catch (...) {
|
||||||
|
if (!std::uncaught_exception())
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AbstractThrowingSessionTransaction(TransactionInterface &interface)
|
||||||
|
: m_interface(interface)
|
||||||
|
{}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TransactionInterface &m_interface;
|
||||||
|
std::unique_lock<TransactionInterface> m_locker{m_interface};
|
||||||
|
bool m_isAlreadyCommited = false;
|
||||||
|
bool m_rollback = false;
|
||||||
|
};
|
||||||
|
|
||||||
class AbstractThrowingTransaction : public AbstractTransaction
|
class AbstractThrowingTransaction : public AbstractTransaction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -181,6 +222,23 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
using ExclusiveTransaction = BasicExclusiveTransaction<AbstractThrowingTransaction>;
|
using ExclusiveTransaction = BasicExclusiveTransaction<AbstractThrowingTransaction>;
|
||||||
using ExclusiveNonThrowingDestructorTransaction = BasicExclusiveTransaction<AbstractNonThrowingDestructorTransaction>;
|
using ExclusiveNonThrowingDestructorTransaction
|
||||||
|
= BasicExclusiveTransaction<AbstractNonThrowingDestructorTransaction>;
|
||||||
|
|
||||||
|
class ImmediateSessionTransaction final : public AbstractThrowingSessionTransaction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImmediateSessionTransaction(TransactionInterface &interface)
|
||||||
|
: AbstractThrowingSessionTransaction(interface)
|
||||||
|
{
|
||||||
|
interface.immediateSessionBegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
~ImmediateSessionTransaction()
|
||||||
|
{
|
||||||
|
AbstractThrowingSessionTransaction::m_rollback
|
||||||
|
= !AbstractThrowingSessionTransaction::m_isAlreadyCommited;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Sqlite
|
} // namespace Sqlite
|
||||||
|
@@ -30,17 +30,29 @@
|
|||||||
|
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace Sqlite {
|
namespace Sqlite {
|
||||||
|
|
||||||
enum class ValueType : unsigned char { Integer, Float, String };
|
enum class ValueType : unsigned char { Null, Integer, Float, String };
|
||||||
|
|
||||||
|
class NullValue
|
||||||
|
{
|
||||||
|
friend bool operator==(NullValue, NullValue) { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
template<typename StringType>
|
template<typename StringType>
|
||||||
class ValueBase
|
class ValueBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using VariantType = Utils::variant<long long, double, StringType>;
|
using VariantType = Utils::variant<NullValue, long long, double, StringType>;
|
||||||
|
|
||||||
|
ValueBase() = default;
|
||||||
|
|
||||||
|
explicit ValueBase(NullValue) {}
|
||||||
|
|
||||||
explicit ValueBase(VariantType &&value)
|
explicit ValueBase(VariantType &&value)
|
||||||
: value(value)
|
: value(value)
|
||||||
@@ -70,6 +82,8 @@ public:
|
|||||||
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
bool isNull() const { return value.index() == 0; }
|
||||||
|
|
||||||
long long toInteger() const { return Utils::get<int(ValueType::Integer)>(value); }
|
long long toInteger() const { return Utils::get<int(ValueType::Integer)>(value); }
|
||||||
|
|
||||||
double toFloat() const { return Utils::get<int(ValueType::Float)>(value); }
|
double toFloat() const { return Utils::get<int(ValueType::Float)>(value); }
|
||||||
@@ -93,6 +107,8 @@ public:
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const ValueBase &first, std::nullptr_t) { return first.isNull(); }
|
||||||
|
|
||||||
friend bool operator==(const ValueBase &first, long long second)
|
friend bool operator==(const ValueBase &first, long long second)
|
||||||
{
|
{
|
||||||
auto maybeInteger = Utils::get_if<int(ValueType::Integer)>(&first.value);
|
auto maybeInteger = Utils::get_if<int(ValueType::Integer)>(&first.value);
|
||||||
@@ -171,10 +187,12 @@ public:
|
|||||||
{
|
{
|
||||||
switch (value.index()) {
|
switch (value.index()) {
|
||||||
case 0:
|
case 0:
|
||||||
return ValueType::Integer;
|
return ValueType::Null;
|
||||||
case 1:
|
case 1:
|
||||||
return ValueType::Float;
|
return ValueType::Integer;
|
||||||
case 2:
|
case 2:
|
||||||
|
return ValueType::Float;
|
||||||
|
case 3:
|
||||||
return ValueType::String;
|
return ValueType::String;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +224,10 @@ class Value : public ValueBase<Utils::SmallString>
|
|||||||
public:
|
public:
|
||||||
using Base::Base;
|
using Base::Base;
|
||||||
|
|
||||||
|
Value() = default;
|
||||||
|
|
||||||
|
explicit Value(NullValue) {}
|
||||||
|
|
||||||
explicit Value(ValueView view)
|
explicit Value(ValueView view)
|
||||||
: ValueBase(convert(view))
|
: ValueBase(convert(view))
|
||||||
{}
|
{}
|
||||||
@@ -226,6 +248,10 @@ public:
|
|||||||
: ValueBase(VariantType{Utils::SmallString(value)})
|
: ValueBase(VariantType{Utils::SmallString(value)})
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
explicit Value(const std::string &value)
|
||||||
|
: ValueBase(VariantType{Utils::SmallString(value)})
|
||||||
|
{}
|
||||||
|
|
||||||
friend bool operator!=(const Value &first, const Value &second)
|
friend bool operator!=(const Value &first, const Value &second)
|
||||||
{
|
{
|
||||||
return !(first.value == second.value);
|
return !(first.value == second.value);
|
||||||
@@ -265,6 +291,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
static Base::VariantType convert(const QVariant &value)
|
static Base::VariantType convert(const QVariant &value)
|
||||||
{
|
{
|
||||||
|
if (value.isNull())
|
||||||
|
return VariantType{NullValue{}};
|
||||||
|
|
||||||
switch (value.type()) {
|
switch (value.type()) {
|
||||||
case QVariant::Int:
|
case QVariant::Int:
|
||||||
return VariantType{static_cast<long long>(value.toInt())};
|
return VariantType{static_cast<long long>(value.toInt())};
|
||||||
@@ -284,6 +313,8 @@ private:
|
|||||||
static Base::VariantType convert(ValueView view)
|
static Base::VariantType convert(ValueView view)
|
||||||
{
|
{
|
||||||
switch (view.type()) {
|
switch (view.type()) {
|
||||||
|
case ValueType::Null:
|
||||||
|
return VariantType(NullValue{});
|
||||||
case ValueType::Integer:
|
case ValueType::Integer:
|
||||||
return VariantType{view.toInteger()};
|
return VariantType{view.toInteger()};
|
||||||
case ValueType::Float:
|
case ValueType::Float:
|
||||||
|
@@ -37,7 +37,6 @@ public:
|
|||||||
using StatementImplementation::execute;
|
using StatementImplementation::execute;
|
||||||
using StatementImplementation::database;
|
using StatementImplementation::database;
|
||||||
using StatementImplementation::write;
|
using StatementImplementation::write;
|
||||||
using StatementImplementation::writeNamed;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void checkIsWritableStatement();
|
void checkIsWritableStatement();
|
||||||
|
49
src/libs/sqlite/tableconstraints.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sqliteglobal.h"
|
||||||
|
|
||||||
|
#include <sqlitevalue.h>
|
||||||
|
#include <utils/smallstringvector.h>
|
||||||
|
#include <utils/variant.h>
|
||||||
|
|
||||||
|
namespace Sqlite {
|
||||||
|
class TablePrimaryKey
|
||||||
|
{
|
||||||
|
friend bool operator==(TablePrimaryKey first, TablePrimaryKey second)
|
||||||
|
{
|
||||||
|
return first.columns == second.columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Utils::SmallStringVector columns;
|
||||||
|
};
|
||||||
|
|
||||||
|
using TableConstraint = Utils::variant<TablePrimaryKey>;
|
||||||
|
using TableConstraints = std::vector<TableConstraint>;
|
||||||
|
|
||||||
|
} // namespace Sqlite
|
@@ -6,6 +6,7 @@ add_qtc_library(Utils
|
|||||||
SOURCES
|
SOURCES
|
||||||
../3rdparty/optional/optional.hpp
|
../3rdparty/optional/optional.hpp
|
||||||
../3rdparty/variant/variant.hpp
|
../3rdparty/variant/variant.hpp
|
||||||
|
../3rdparty/span/span.hpp
|
||||||
QtConcurrentTools
|
QtConcurrentTools
|
||||||
algorithm.h
|
algorithm.h
|
||||||
ansiescapecodehandler.cpp ansiescapecodehandler.h
|
ansiescapecodehandler.cpp ansiescapecodehandler.h
|
||||||
@@ -137,6 +138,7 @@ add_qtc_library(Utils
|
|||||||
smallstringmemory.h
|
smallstringmemory.h
|
||||||
smallstringvector.h
|
smallstringvector.h
|
||||||
smallstringview.h
|
smallstringview.h
|
||||||
|
span.h
|
||||||
statuslabel.cpp statuslabel.h
|
statuslabel.cpp statuslabel.h
|
||||||
stringutils.cpp stringutils.h
|
stringutils.cpp stringutils.h
|
||||||
styledbar.cpp styledbar.h
|
styledbar.cpp styledbar.h
|
||||||
|
@@ -90,39 +90,35 @@ public:
|
|||||||
constexpr
|
constexpr
|
||||||
BasicSmallString(const char(&string)[ArraySize])
|
BasicSmallString(const char(&string)[ArraySize])
|
||||||
: m_data(string)
|
: m_data(string)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
BasicSmallString(const char *string, size_type size, size_type capacity)
|
BasicSmallString(const char *string, size_type size, size_type capacity)
|
||||||
{
|
{
|
||||||
if (Q_LIKELY(capacity <= shortStringCapacity())) {
|
if (Q_LIKELY(capacity <= shortStringCapacity())) {
|
||||||
std::memcpy(m_data.shortString.string, string, size);
|
std::char_traits<char>::copy(m_data.shortString.string, string, size);
|
||||||
m_data.shortString.string[size] = 0;
|
m_data.shortString.string[size] = 0;
|
||||||
m_data.shortString.control.setShortStringSize(size);
|
m_data.shortString.control.setShortStringSize(size);
|
||||||
m_data.shortString.control.setIsShortString(true);
|
m_data.shortString.control.setIsShortString(true);
|
||||||
m_data.shortString.control.setIsReadOnlyReference(false);
|
m_data.shortString.control.setIsReadOnlyReference(false);
|
||||||
} else {
|
} else {
|
||||||
m_data.allocated.data.pointer = Memory::allocate(capacity + 1);
|
m_data.allocated.data.pointer = Memory::allocate(capacity + 1);
|
||||||
std::memcpy(m_data.allocated.data.pointer, string, size);
|
std::char_traits<char>::copy(m_data.allocated.data.pointer, string, size);
|
||||||
initializeLongString(size, capacity);
|
initializeLongString(size, capacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit BasicSmallString(SmallStringView stringView)
|
explicit BasicSmallString(SmallStringView stringView)
|
||||||
: BasicSmallString(stringView.data(), stringView.size(), stringView.size())
|
: BasicSmallString(stringView.data(), stringView.size(), stringView.size())
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
BasicSmallString(const char *string, size_type size)
|
BasicSmallString(const char *string, size_type size)
|
||||||
: BasicSmallString(string, size, size)
|
: BasicSmallString(string, size, size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type,
|
template<typename Type, typename = std::enable_if_t<std::is_pointer<Type>::value>>
|
||||||
typename = std::enable_if_t<std::is_pointer<Type>::value>
|
|
||||||
>
|
|
||||||
BasicSmallString(Type characterPointer)
|
BasicSmallString(Type characterPointer)
|
||||||
: BasicSmallString(characterPointer, std::strlen(characterPointer))
|
: BasicSmallString(characterPointer, std::char_traits<char>::length(characterPointer))
|
||||||
{
|
{
|
||||||
static_assert(!std::is_array<Type>::value, "Input type is array and not char pointer!");
|
static_assert(!std::is_array<Type>::value, "Input type is array and not char pointer!");
|
||||||
}
|
}
|
||||||
@@ -211,8 +207,7 @@ public:
|
|||||||
return clonedString;
|
return clonedString;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend
|
friend void swap(BasicSmallString &first, BasicSmallString &second) noexcept
|
||||||
void swap(BasicSmallString &first, BasicSmallString &second)
|
|
||||||
{
|
{
|
||||||
using std::swap;
|
using std::swap;
|
||||||
|
|
||||||
@@ -254,7 +249,7 @@ public:
|
|||||||
static
|
static
|
||||||
BasicSmallString fromUtf8(const char *characterPointer)
|
BasicSmallString fromUtf8(const char *characterPointer)
|
||||||
{
|
{
|
||||||
return BasicSmallString(characterPointer, std::strlen(characterPointer));
|
return BasicSmallString(characterPointer, std::char_traits<char>::length(characterPointer));
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve(size_type newCapacity)
|
void reserve(size_type newCapacity)
|
||||||
@@ -272,7 +267,7 @@ public:
|
|||||||
const char *oldData = data();
|
const char *oldData = data();
|
||||||
|
|
||||||
char *newData = Memory::allocate(newCapacity + 1);
|
char *newData = Memory::allocate(newCapacity + 1);
|
||||||
std::memcpy(newData, oldData, oldSize);
|
std::char_traits<char>::copy(newData, oldData, oldSize);
|
||||||
m_data.allocated.data.pointer = newData;
|
m_data.allocated.data.pointer = newData;
|
||||||
initializeLongString(oldSize, newCapacity);
|
initializeLongString(oldSize, newCapacity);
|
||||||
}
|
}
|
||||||
@@ -381,7 +376,7 @@ public:
|
|||||||
|
|
||||||
bool contains(char characterToSearch) const
|
bool contains(char characterToSearch) const
|
||||||
{
|
{
|
||||||
auto found = std::memchr(data(), characterToSearch, size());
|
auto found = std::char_traits<char>::find(data(), size(), characterToSearch);
|
||||||
|
|
||||||
return found != nullptr;
|
return found != nullptr;
|
||||||
}
|
}
|
||||||
@@ -389,7 +384,9 @@ public:
|
|||||||
bool startsWith(SmallStringView subStringToSearch) const noexcept
|
bool startsWith(SmallStringView subStringToSearch) const noexcept
|
||||||
{
|
{
|
||||||
if (size() >= subStringToSearch.size())
|
if (size() >= subStringToSearch.size())
|
||||||
return !std::memcmp(data(), subStringToSearch.data(), subStringToSearch.size());
|
return !std::char_traits<char>::compare(data(),
|
||||||
|
subStringToSearch.data(),
|
||||||
|
subStringToSearch.size());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -402,7 +399,8 @@ public:
|
|||||||
bool endsWith(SmallStringView subStringToSearch) const noexcept
|
bool endsWith(SmallStringView subStringToSearch) const noexcept
|
||||||
{
|
{
|
||||||
if (size() >= subStringToSearch.size()) {
|
if (size() >= subStringToSearch.size()) {
|
||||||
const int comparison = std::memcmp(end().data() - subStringToSearch.size(),
|
const int comparison = std::char_traits<char>::compare(end().data()
|
||||||
|
- subStringToSearch.size(),
|
||||||
subStringToSearch.data(),
|
subStringToSearch.data(),
|
||||||
subStringToSearch.size());
|
subStringToSearch.size());
|
||||||
return comparison == 0;
|
return comparison == 0;
|
||||||
@@ -463,7 +461,7 @@ public:
|
|||||||
size_type newSize = oldSize + string.size();
|
size_type newSize = oldSize + string.size();
|
||||||
|
|
||||||
reserve(optimalCapacity(newSize));
|
reserve(optimalCapacity(newSize));
|
||||||
std::memcpy(data() + oldSize, string.data(), string.size());
|
std::char_traits<char>::copy(data() + oldSize, string.data(), string.size());
|
||||||
at(newSize) = 0;
|
at(newSize) = 0;
|
||||||
setSize(newSize);
|
setSize(newSize);
|
||||||
}
|
}
|
||||||
@@ -725,7 +723,7 @@ private:
|
|||||||
at(size) = 0;
|
at(size) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initializeLongString(size_type size, size_type capacity)
|
constexpr void initializeLongString(size_type size, size_type capacity)
|
||||||
{
|
{
|
||||||
m_data.allocated.data.pointer[size] = 0;
|
m_data.allocated.data.pointer[size] = 0;
|
||||||
m_data.allocated.data.size = size;
|
m_data.allocated.data.size = size;
|
||||||
@@ -758,7 +756,7 @@ private:
|
|||||||
while (found != end()) {
|
while (found != end()) {
|
||||||
start = found + toText.size();
|
start = found + toText.size();
|
||||||
|
|
||||||
std::memcpy(found.data(), toText.data(), toText.size());
|
std::char_traits<char>::copy(found.data(), toText.data(), toText.size());
|
||||||
|
|
||||||
found = std::search(start,
|
found = std::search(start,
|
||||||
end(),
|
end(),
|
||||||
|
@@ -25,6 +25,18 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
#define constexpr17 constexpr
|
||||||
|
#else
|
||||||
|
#define constexpr17 inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cplusplus >= 202002L
|
||||||
|
#define constexpr20 constexpr
|
||||||
|
#else
|
||||||
|
#define constexpr20 inline
|
||||||
|
#endif
|
||||||
|
|
||||||
using uint = unsigned int;
|
using uint = unsigned int;
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
@@ -35,9 +47,4 @@ class BasicSmallString;
|
|||||||
using SmallString = BasicSmallString<31>;
|
using SmallString = BasicSmallString<31>;
|
||||||
using PathString = BasicSmallString<190>;
|
using PathString = BasicSmallString<190>;
|
||||||
|
|
||||||
inline
|
|
||||||
int compare(SmallStringView first, SmallStringView second) noexcept;
|
|
||||||
inline
|
|
||||||
int reverseCompare(SmallStringView first, SmallStringView second) noexcept;
|
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
@@ -230,30 +230,6 @@ QDataStream &operator>>(QDataStream &in, vector<Type> &vector)
|
|||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
ostream &operator<<(ostream &out, const vector<T> &vector)
|
|
||||||
{
|
|
||||||
out << "[";
|
|
||||||
|
|
||||||
for (auto current = vector.begin(); current != vector.end(); ++current) {
|
|
||||||
std::ostringstream entryStream;
|
|
||||||
entryStream << *current;
|
|
||||||
std::string entryString = entryStream.str();
|
|
||||||
|
|
||||||
if (entryString.size() > 4)
|
|
||||||
out << "\n\t";
|
|
||||||
|
|
||||||
out << entryString;
|
|
||||||
|
|
||||||
if (std::next(current) != vector.end())
|
|
||||||
out << ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
out << "]";
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
@@ -32,123 +32,94 @@ namespace Utils {
|
|||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
template <class Category,
|
template<class Category,
|
||||||
class Type,
|
class Type,
|
||||||
typename DistanceType = ptrdiff_t,
|
typename DistanceType = ptrdiff_t,
|
||||||
typename Pointer = Type*,
|
typename Pointer = Type *,
|
||||||
typename Reference = Type&>
|
typename Reference = Type &>
|
||||||
struct SmallStringIterator : public std::iterator<Category, Type, DistanceType, Pointer, Reference>
|
struct SmallStringIterator
|
||||||
{
|
{
|
||||||
constexpr
|
using iterator_category = Category;
|
||||||
SmallStringIterator() noexcept = default;
|
using value_type = Type;
|
||||||
|
using difference_type = DistanceType;
|
||||||
|
using pointer = Pointer;
|
||||||
|
using reference = Reference;
|
||||||
|
|
||||||
constexpr
|
constexpr SmallStringIterator() noexcept = default;
|
||||||
SmallStringIterator(Pointer ptr) noexcept : pointer_(ptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SmallStringIterator operator++() noexcept
|
constexpr SmallStringIterator(Pointer ptr) noexcept
|
||||||
{
|
: pointer_(ptr)
|
||||||
return ++pointer_;
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
SmallStringIterator operator++(int) noexcept
|
constexpr SmallStringIterator operator++() noexcept { return ++pointer_; }
|
||||||
{
|
|
||||||
return pointer_++;
|
|
||||||
}
|
|
||||||
|
|
||||||
SmallStringIterator operator--() noexcept
|
constexpr SmallStringIterator operator++(int) noexcept { return pointer_++; }
|
||||||
{
|
|
||||||
return --pointer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
SmallStringIterator operator--(int) noexcept
|
constexpr SmallStringIterator operator--() noexcept { return --pointer_; }
|
||||||
{
|
|
||||||
return pointer_--;
|
|
||||||
}
|
|
||||||
|
|
||||||
SmallStringIterator operator+(DistanceType difference) const noexcept
|
constexpr SmallStringIterator operator--(int) noexcept { return pointer_--; }
|
||||||
|
|
||||||
|
constexpr SmallStringIterator operator+(DistanceType difference) const noexcept
|
||||||
{
|
{
|
||||||
return pointer_ + difference;
|
return pointer_ + difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallStringIterator operator-(DistanceType difference) const noexcept
|
constexpr SmallStringIterator operator-(DistanceType difference) const noexcept
|
||||||
{
|
{
|
||||||
return pointer_ - difference;
|
return pointer_ - difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallStringIterator operator+(std::size_t difference) const noexcept
|
constexpr SmallStringIterator operator+(std::size_t difference) const noexcept
|
||||||
{
|
{
|
||||||
return pointer_ + difference;
|
return pointer_ + difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallStringIterator operator-(std::size_t difference) const noexcept
|
constexpr SmallStringIterator operator-(std::size_t difference) const noexcept
|
||||||
{
|
{
|
||||||
return pointer_ - difference;
|
return pointer_ - difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
DistanceType operator-(SmallStringIterator other) const noexcept
|
constexpr DistanceType operator-(SmallStringIterator other) const noexcept
|
||||||
{
|
{
|
||||||
return pointer_ - other.data();
|
return pointer_ - other.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallStringIterator operator+=(DistanceType difference) noexcept
|
constexpr SmallStringIterator operator+=(DistanceType difference) noexcept
|
||||||
{
|
{
|
||||||
return pointer_ += difference;
|
return pointer_ += difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallStringIterator operator-=(DistanceType difference) noexcept
|
constexpr SmallStringIterator operator-=(DistanceType difference) noexcept
|
||||||
{
|
{
|
||||||
return pointer_ -= difference;
|
return pointer_ -= difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference operator*() noexcept
|
constexpr Reference operator*() noexcept { return *pointer_; }
|
||||||
{
|
|
||||||
return *pointer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Reference operator*() const noexcept
|
const Reference operator*() const noexcept { return *pointer_; }
|
||||||
{
|
|
||||||
return *pointer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pointer operator->() noexcept
|
constexpr Pointer operator->() noexcept { return pointer_; }
|
||||||
{
|
|
||||||
return pointer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Pointer operator->() const noexcept
|
constexpr const Pointer operator->() const noexcept { return pointer_; }
|
||||||
{
|
|
||||||
return pointer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr
|
constexpr bool operator==(SmallStringIterator other) const noexcept
|
||||||
bool operator==(SmallStringIterator other) const noexcept
|
|
||||||
{
|
{
|
||||||
return pointer_ == other.pointer_;
|
return pointer_ == other.pointer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr
|
constexpr bool operator!=(SmallStringIterator other) const noexcept
|
||||||
bool operator!=(SmallStringIterator other) const noexcept
|
|
||||||
{
|
{
|
||||||
return pointer_ != other.pointer_;
|
return pointer_ != other.pointer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr
|
constexpr bool operator<(SmallStringIterator other) const noexcept
|
||||||
bool operator<(SmallStringIterator other) const noexcept
|
|
||||||
{
|
{
|
||||||
return pointer_ < other.pointer_;
|
return pointer_ < other.pointer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pointer data() noexcept
|
constexpr Pointer data() noexcept { return pointer_; }
|
||||||
{
|
|
||||||
return pointer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Pointer data() const noexcept
|
constexpr const Pointer data() const noexcept { return pointer_; }
|
||||||
{
|
|
||||||
return pointer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pointer pointer_ = nullptr;
|
Pointer pointer_ = nullptr;
|
||||||
|
@@ -49,30 +49,21 @@ struct ControlBlock
|
|||||||
m_isReference(isReference)
|
m_isReference(isReference)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void setShortStringSize(size_type size)
|
constexpr void setShortStringSize(size_type size)
|
||||||
{
|
{
|
||||||
m_shortStringSize = static_cast<SizeType>(size);
|
m_shortStringSize = static_cast<SizeType>(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type shortStringSize() const
|
constexpr size_type shortStringSize() const { return m_shortStringSize; }
|
||||||
{
|
|
||||||
return m_shortStringSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setIsReadOnlyReference(bool isReadOnlyReference)
|
constexpr void setIsReadOnlyReference(bool isReadOnlyReference)
|
||||||
{
|
{
|
||||||
m_isReadOnlyReference = isReadOnlyReference;
|
m_isReadOnlyReference = isReadOnlyReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setIsReference(bool isReference)
|
constexpr void setIsReference(bool isReference) { m_isReference = isReference; }
|
||||||
{
|
|
||||||
m_isReference = isReference;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setIsShortString(bool isShortString)
|
constexpr void setIsShortString(bool isShortString) { m_isReference = !isShortString; }
|
||||||
{
|
|
||||||
m_isReference = !isShortString;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr
|
constexpr
|
||||||
SizeType stringSize() const
|
SizeType stringSize() const
|
||||||
@@ -168,7 +159,7 @@ struct StringDataLayout {
|
|||||||
|
|
||||||
template<size_type Size,
|
template<size_type Size,
|
||||||
typename std::enable_if_t<Size <= MaximumShortStringDataAreaSize, int> = 0>
|
typename std::enable_if_t<Size <= MaximumShortStringDataAreaSize, int> = 0>
|
||||||
StringDataLayout(const char(&string)[Size]) noexcept
|
constexpr StringDataLayout(const char (&string)[Size]) noexcept
|
||||||
: shortString(ShortStringLayout<MaximumShortStringDataAreaSize>{})
|
: shortString(ShortStringLayout<MaximumShortStringDataAreaSize>{})
|
||||||
{
|
{
|
||||||
for (size_type i = 0; i < Size; ++i)
|
for (size_type i = 0; i < Size; ++i)
|
||||||
|
@@ -37,34 +37,24 @@ namespace Memory {
|
|||||||
|
|
||||||
inline char *allocate(std::size_t size)
|
inline char *allocate(std::size_t size)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN32
|
|
||||||
return static_cast<char*>(_aligned_malloc(size, 64));
|
|
||||||
#else
|
|
||||||
return static_cast<char*>(std::malloc(size));
|
return static_cast<char*>(std::malloc(size));
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void deallocate(char *memory)
|
inline void deallocate(char *memory)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN32
|
|
||||||
_aligned_free(memory);
|
|
||||||
#else
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
|
#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
|
||||||
#endif
|
#endif
|
||||||
std::free(memory);
|
std::free(memory);
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline char *reallocate(char *oldMemory, std::size_t newSize)
|
inline char *reallocate(char *oldMemory, std::size_t newSize)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN32
|
return static_cast<char *>(std::realloc(oldMemory, newSize));
|
||||||
return static_cast<char*>(_aligned_realloc(oldMemory, newSize, 64));
|
|
||||||
#else
|
|
||||||
return static_cast<char*>(std::realloc(oldMemory, newSize));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "smallstringfwd.h"
|
||||||
#include "smallstringiterator.h"
|
#include "smallstringiterator.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@@ -53,49 +54,32 @@ public:
|
|||||||
|
|
||||||
constexpr SmallStringView() = default;
|
constexpr SmallStringView() = default;
|
||||||
|
|
||||||
template<size_type Size>
|
constexpr17 SmallStringView(const char *characterPointer) noexcept
|
||||||
constexpr
|
: m_pointer(characterPointer)
|
||||||
SmallStringView(const char(&string)[Size]) noexcept
|
, m_size(std::char_traits<char>::length(characterPointer))
|
||||||
: m_pointer(string),
|
|
||||||
m_size(Size - 1)
|
|
||||||
{
|
|
||||||
static_assert(Size >= 1, "Invalid string literal! Length is zero!");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Type,
|
|
||||||
typename = std::enable_if_t<std::is_pointer<Type>::value>
|
|
||||||
>
|
|
||||||
SmallStringView(Type characterPointer) noexcept
|
|
||||||
: m_pointer(characterPointer),
|
|
||||||
m_size(std::strlen(characterPointer))
|
|
||||||
{
|
|
||||||
static_assert(!std::is_array<Type>::value, "Input type is array and not char pointer!");
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr
|
|
||||||
SmallStringView(const char *const string, const size_type size) noexcept
|
|
||||||
: m_pointer(string),
|
|
||||||
m_size(size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SmallStringView(const const_iterator begin, const const_iterator end) noexcept
|
|
||||||
: m_pointer(begin.data()),
|
|
||||||
m_size(std::size_t(end - begin))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename String,
|
|
||||||
typename Utils::enable_if_has_char_data_pointer<String> = 0>
|
|
||||||
SmallStringView(const String &string) noexcept
|
|
||||||
: m_pointer(string.data()),
|
|
||||||
m_size(string.size())
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static
|
constexpr SmallStringView(const char *const string, const size_type size) noexcept
|
||||||
SmallStringView fromUtf8(const char *const characterPointer)
|
: m_pointer(string)
|
||||||
|
, m_size(size)
|
||||||
{
|
{
|
||||||
return SmallStringView(characterPointer, std::strlen(characterPointer));
|
}
|
||||||
|
|
||||||
|
constexpr SmallStringView(const const_iterator begin, const const_iterator end) noexcept
|
||||||
|
: m_pointer(begin.data())
|
||||||
|
, m_size(std::size_t(end - begin))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename String, typename Utils::enable_if_has_char_data_pointer<String> = 0>
|
||||||
|
constexpr SmallStringView(const String &string) noexcept
|
||||||
|
: m_pointer(string.data())
|
||||||
|
, m_size(string.size())
|
||||||
|
{}
|
||||||
|
|
||||||
|
static constexpr17 SmallStringView fromUtf8(const char *const characterPointer)
|
||||||
|
{
|
||||||
|
return SmallStringView(characterPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr
|
constexpr
|
||||||
@@ -146,93 +130,85 @@ public:
|
|||||||
return data() + size();
|
return data() + size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const_reverse_iterator rbegin() const noexcept
|
constexpr17 const_reverse_iterator rbegin() const noexcept
|
||||||
{
|
{
|
||||||
return const_reverse_iterator(end());
|
return const_reverse_iterator(end());
|
||||||
}
|
}
|
||||||
|
|
||||||
const_reverse_iterator rend() const noexcept
|
constexpr17 const_reverse_iterator rend() const noexcept
|
||||||
{
|
{
|
||||||
return const_reverse_iterator(begin());
|
return const_reverse_iterator(begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
operator std::string() const
|
constexpr20 operator std::string() const { return std::string(data(), size()); }
|
||||||
{
|
|
||||||
return std::string(data(), size());
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit operator QString() const
|
explicit operator QString() const
|
||||||
{
|
{
|
||||||
return QString::fromUtf8(data(), int(size()));
|
return QString::fromUtf8(data(), int(size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool startsWith(SmallStringView subStringToSearch) const noexcept
|
constexpr17 bool startsWith(SmallStringView subStringToSearch) const noexcept
|
||||||
{
|
{
|
||||||
if (size() >= subStringToSearch.size())
|
if (size() >= subStringToSearch.size())
|
||||||
return !std::memcmp(m_pointer, subStringToSearch.data(), subStringToSearch.size());
|
return !std::char_traits<char>::compare(m_pointer,
|
||||||
|
subStringToSearch.data(),
|
||||||
|
subStringToSearch.size());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool startsWith(char characterToSearch) const noexcept
|
constexpr bool startsWith(char characterToSearch) const noexcept
|
||||||
{
|
{
|
||||||
return m_pointer[0] == characterToSearch;
|
return m_pointer[0] == characterToSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
char back() const { return m_pointer[m_size - 1]; }
|
constexpr char back() const { return m_pointer[m_size - 1]; }
|
||||||
|
|
||||||
char operator[](std::size_t index) { return m_pointer[index]; }
|
constexpr char operator[](std::size_t index) { return m_pointer[index]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *m_pointer = "";
|
const char *m_pointer = "";
|
||||||
size_type m_size = 0;
|
size_type m_size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
constexpr17 bool operator==(SmallStringView first, SmallStringView second) noexcept
|
||||||
bool operator==(SmallStringView first, SmallStringView second) noexcept
|
|
||||||
{
|
{
|
||||||
return first.size() == second.size() && std::memcmp(first.data(), second.data(), first.size()) == 0;
|
return first.size() == second.size()
|
||||||
|
&& std::char_traits<char>::compare(first.data(), second.data(), first.size()) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
constexpr17 bool operator!=(SmallStringView first, SmallStringView second) noexcept
|
||||||
bool operator!=(SmallStringView first, SmallStringView second) noexcept
|
|
||||||
{
|
{
|
||||||
return !(first == second);
|
return !(first == second);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
constexpr17 int compare(SmallStringView first, SmallStringView second) noexcept
|
||||||
int compare(SmallStringView first, SmallStringView second) noexcept
|
|
||||||
{
|
{
|
||||||
int sizeDifference = int(first.size() - second.size());
|
int sizeDifference = int(first.size() - second.size());
|
||||||
|
|
||||||
if (sizeDifference == 0)
|
if (sizeDifference == 0)
|
||||||
return std::memcmp(first.data(), second.data(), first.size());
|
return std::char_traits<char>::compare(first.data(), second.data(), first.size());
|
||||||
|
|
||||||
return sizeDifference;
|
return sizeDifference;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
constexpr17 bool operator<(SmallStringView first, SmallStringView second) noexcept
|
||||||
bool operator<(SmallStringView first, SmallStringView second) noexcept
|
|
||||||
{
|
{
|
||||||
return compare(first, second) < 0;
|
return compare(first, second) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
constexpr17 bool operator>(SmallStringView first, SmallStringView second) noexcept
|
||||||
bool operator>(SmallStringView first, SmallStringView second) noexcept
|
|
||||||
{
|
{
|
||||||
return second < first;
|
return second < first;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
inline
|
constexpr int reverse_memcmp(const char *first, const char *second, size_t n)
|
||||||
int reverse_memcmp(const char *first, const char *second, size_t n)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
const char *currentFirst = first + n - 1;
|
const char *currentFirst = first + n - 1;
|
||||||
const char *currentSecond = second + n - 1;
|
const char *currentSecond = second + n - 1;
|
||||||
|
|
||||||
while (n > 0)
|
while (n > 0) {
|
||||||
{
|
|
||||||
// If the current characters differ, return an appropriately signed
|
// If the current characters differ, return an appropriately signed
|
||||||
// value; otherwise, keep searching backwards
|
// value; otherwise, keep searching backwards
|
||||||
int difference = *currentFirst - *currentSecond;
|
int difference = *currentFirst - *currentSecond;
|
||||||
@@ -246,10 +222,9 @@ int reverse_memcmp(const char *first, const char *second, size_t n)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Internal
|
||||||
|
|
||||||
inline
|
constexpr int reverseCompare(SmallStringView first, SmallStringView second) noexcept
|
||||||
int reverseCompare(SmallStringView first, SmallStringView second) noexcept
|
|
||||||
{
|
{
|
||||||
int sizeDifference = int(first.size() - second.size());
|
int sizeDifference = int(first.size() - second.size());
|
||||||
|
|
||||||
@@ -261,10 +236,7 @@ int reverseCompare(SmallStringView first, SmallStringView second) noexcept
|
|||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|
||||||
#ifdef __cpp_user_defined_literals
|
|
||||||
inline
|
|
||||||
constexpr Utils::SmallStringView operator""_sv(const char *const string, size_t size)
|
constexpr Utils::SmallStringView operator""_sv(const char *const string, size_t size)
|
||||||
{
|
{
|
||||||
return Utils::SmallStringView(string, size);
|
return Utils::SmallStringView(string, size);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
40
src/libs/utils/span.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if __cplusplus >= 202002L
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
namespace Utils {
|
||||||
|
using std::as_bytes;
|
||||||
|
using std::as_writable_bytes;
|
||||||
|
using std::get;
|
||||||
|
using std::span;
|
||||||
|
} // namespace Utils
|
||||||
|
#else
|
||||||
|
#define TCB_SPAN_NAMESPACE_NAME Utils
|
||||||
|
#include <3rdparty/span/span.hpp>
|
||||||
|
#endif
|
@@ -152,6 +152,8 @@ HEADERS += \
|
|||||||
$$PWD/pointeralgorithm.h \
|
$$PWD/pointeralgorithm.h \
|
||||||
$$PWD/qrcparser.h \
|
$$PWD/qrcparser.h \
|
||||||
$$PWD/qtcprocess.h \
|
$$PWD/qtcprocess.h \
|
||||||
|
$$PWD/span.h \
|
||||||
|
$$PWD/../3rdparty/span/span.hpp \
|
||||||
$$PWD/utils_global.h \
|
$$PWD/utils_global.h \
|
||||||
$$PWD/reloadpromptutils.h \
|
$$PWD/reloadpromptutils.h \
|
||||||
$$PWD/settingsaccessor.h \
|
$$PWD/settingsaccessor.h \
|
||||||
|
@@ -245,6 +245,8 @@ Project {
|
|||||||
"smallstringlayout.h",
|
"smallstringlayout.h",
|
||||||
"smallstringmemory.h",
|
"smallstringmemory.h",
|
||||||
"smallstringvector.h",
|
"smallstringvector.h",
|
||||||
|
"span.h",
|
||||||
|
"../3rdparty/span/span.hpp",
|
||||||
"statuslabel.cpp",
|
"statuslabel.cpp",
|
||||||
"statuslabel.h",
|
"statuslabel.h",
|
||||||
"stringutils.cpp",
|
"stringutils.cpp",
|
||||||
|
@@ -37,6 +37,7 @@ using std::get;
|
|||||||
using std::get_if;
|
using std::get_if;
|
||||||
using std::holds_alternative;
|
using std::holds_alternative;
|
||||||
using std::variant;
|
using std::variant;
|
||||||
|
using std::visit;
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -47,6 +48,7 @@ using mpark::get;
|
|||||||
using mpark::get_if;
|
using mpark::get_if;
|
||||||
using mpark::holds_alternative;
|
using mpark::holds_alternative;
|
||||||
using mpark::variant;
|
using mpark::variant;
|
||||||
|
using mpark::visit;
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -134,6 +134,8 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
reparentinstancescommand.cpp reparentinstancescommand.h
|
reparentinstancescommand.cpp reparentinstancescommand.h
|
||||||
statepreviewimagechangedcommand.cpp statepreviewimagechangedcommand.h
|
statepreviewimagechangedcommand.cpp statepreviewimagechangedcommand.h
|
||||||
synchronizecommand.cpp synchronizecommand.h
|
synchronizecommand.cpp synchronizecommand.h
|
||||||
|
changepreviewimagesizecommand.cpp changepreviewimagesizecommand.h
|
||||||
|
changelanguagecommand.cpp changelanguagecommand.h
|
||||||
tokencommand.cpp tokencommand.h
|
tokencommand.cpp tokencommand.h
|
||||||
valueschangedcommand.cpp valueschangedcommand.h
|
valueschangedcommand.cpp valueschangedcommand.h
|
||||||
changeselectioncommand.cpp changeselectioncommand.h
|
changeselectioncommand.cpp changeselectioncommand.h
|
||||||
@@ -457,6 +459,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
include/rewriterview.h
|
include/rewriterview.h
|
||||||
include/rewritingexception.h
|
include/rewritingexception.h
|
||||||
include/signalhandlerproperty.h
|
include/signalhandlerproperty.h
|
||||||
|
include/stylesheetmerger.h
|
||||||
include/subcomponentmanager.h
|
include/subcomponentmanager.h
|
||||||
include/textmodifier.h
|
include/textmodifier.h
|
||||||
include/variantproperty.h
|
include/variantproperty.h
|
||||||
@@ -530,6 +533,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
model/rewriteactioncompressor.cpp model/rewriteactioncompressor.h
|
model/rewriteactioncompressor.cpp model/rewriteactioncompressor.h
|
||||||
model/rewriterview.cpp
|
model/rewriterview.cpp
|
||||||
model/signalhandlerproperty.cpp
|
model/signalhandlerproperty.cpp
|
||||||
|
model/stylesheetmerger.cpp
|
||||||
model/textmodifier.cpp
|
model/textmodifier.cpp
|
||||||
model/texttomodelmerger.cpp model/texttomodelmerger.h
|
model/texttomodelmerger.cpp model/texttomodelmerger.h
|
||||||
model/variantproperty.cpp
|
model/variantproperty.cpp
|
||||||
@@ -557,6 +561,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
SOURCES_PREFIX components/annotationeditor
|
SOURCES_PREFIX components/annotationeditor
|
||||||
SOURCES annotationcommenttab.cpp annotationcommenttab.h annotationcommenttab.ui
|
SOURCES annotationcommenttab.cpp annotationcommenttab.h annotationcommenttab.ui
|
||||||
annotationeditordialog.cpp annotationeditordialog.h annotationeditordialog.ui
|
annotationeditordialog.cpp annotationeditordialog.h annotationeditordialog.ui
|
||||||
|
globalannotationeditordialog.cpp globalannotationeditordialog.h globalannotationeditordialog.ui
|
||||||
annotationeditor.cpp annotationeditor.h
|
annotationeditor.cpp annotationeditor.h
|
||||||
annotationtool.cpp annotationtool.h
|
annotationtool.cpp annotationtool.h
|
||||||
globalannotationeditor.cpp globalannotationeditor.h
|
globalannotationeditor.cpp globalannotationeditor.h
|
||||||
|
@@ -79,7 +79,7 @@ void AnnotationCommentTab::resetUI()
|
|||||||
{
|
{
|
||||||
ui->titleEdit->setText(m_comment.title());
|
ui->titleEdit->setText(m_comment.title());
|
||||||
ui->authorEdit->setText(m_comment.author());
|
ui->authorEdit->setText(m_comment.author());
|
||||||
m_editor->setRichText(m_comment.text());
|
m_editor->setRichText(m_comment.deescapedText());
|
||||||
|
|
||||||
if (m_comment.timestamp() > 0)
|
if (m_comment.timestamp() > 0)
|
||||||
ui->timeLabel->setText(m_comment.timestampStr());
|
ui->timeLabel->setText(m_comment.timestampStr());
|
||||||
|
@@ -3,12 +3,15 @@ HEADERS += $$PWD/annotationcommenttab.h
|
|||||||
HEADERS += $$PWD/annotationeditordialog.h
|
HEADERS += $$PWD/annotationeditordialog.h
|
||||||
HEADERS += $$PWD/annotationeditor.h
|
HEADERS += $$PWD/annotationeditor.h
|
||||||
HEADERS += $$PWD/globalannotationeditor.h
|
HEADERS += $$PWD/globalannotationeditor.h
|
||||||
|
HEADERS += $$PWD/globalannotationeditordialog.h
|
||||||
|
|
||||||
SOURCES += $$PWD/annotationtool.cpp
|
SOURCES += $$PWD/annotationtool.cpp
|
||||||
SOURCES += $$PWD/annotationcommenttab.cpp
|
SOURCES += $$PWD/annotationcommenttab.cpp
|
||||||
SOURCES += $$PWD/annotationeditordialog.cpp
|
SOURCES += $$PWD/annotationeditordialog.cpp
|
||||||
SOURCES += $$PWD/annotationeditor.cpp
|
SOURCES += $$PWD/annotationeditor.cpp
|
||||||
SOURCES += $$PWD/globalannotationeditor.cpp
|
SOURCES += $$PWD/globalannotationeditor.cpp
|
||||||
|
SOURCES += $$PWD/globalannotationeditordialog.cpp
|
||||||
|
|
||||||
FORMS += $$PWD/annotationcommenttab.ui
|
FORMS += $$PWD/annotationcommenttab.ui
|
||||||
FORMS += $$PWD/annotationeditordialog.ui
|
FORMS += $$PWD/annotationeditordialog.ui
|
||||||
|
FORMS += $$PWD/globalannotationeditordialog.ui
|
||||||
|
@@ -40,12 +40,11 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation, EditorMode mode)
|
AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, ui(new Ui::AnnotationEditorDialog)
|
, ui(new Ui::AnnotationEditorDialog)
|
||||||
, m_customId(customId)
|
, m_customId(customId)
|
||||||
, m_annotation(annotation)
|
, m_annotation(annotation)
|
||||||
, m_editorMode(mode)
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
@@ -98,8 +97,8 @@ AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &t
|
|||||||
ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner);
|
ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner);
|
||||||
ui->targetIdEdit->setText(targetId);
|
ui->targetIdEdit->setText(targetId);
|
||||||
|
|
||||||
changeEditorMode(m_editorMode);
|
|
||||||
fillFields();
|
fillFields();
|
||||||
|
setWindowTitle(annotationEditorTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnnotationEditorDialog::~AnnotationEditorDialog()
|
AnnotationEditorDialog::~AnnotationEditorDialog()
|
||||||
@@ -129,39 +128,6 @@ QString AnnotationEditorDialog::customId() const
|
|||||||
return m_customId;
|
return m_customId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnnotationEditorDialog::changeEditorMode(AnnotationEditorDialog::EditorMode mode)
|
|
||||||
{
|
|
||||||
switch (mode) {
|
|
||||||
case ItemAnnotation: {
|
|
||||||
ui->customIdEdit->setVisible(true);
|
|
||||||
ui->customIdLabel->setVisible(true);
|
|
||||||
ui->targetIdEdit->setVisible(true);
|
|
||||||
ui->targetIdLabel->setVisible(true);
|
|
||||||
setWindowTitle(annotationEditorTitle);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GlobalAnnotation: {
|
|
||||||
ui->customIdEdit->clear();
|
|
||||||
ui->targetIdEdit->clear();
|
|
||||||
ui->customIdEdit->setVisible(false);
|
|
||||||
ui->customIdLabel->setVisible(false);
|
|
||||||
ui->targetIdEdit->setVisible(false);
|
|
||||||
ui->targetIdLabel->setVisible(false);
|
|
||||||
setWindowTitle(globalEditorTitle);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_editorMode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnnotationEditorDialog::EditorMode AnnotationEditorDialog::editorMode() const
|
|
||||||
{
|
|
||||||
return m_editorMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnnotationEditorDialog::acceptedClicked()
|
void AnnotationEditorDialog::acceptedClicked()
|
||||||
{
|
{
|
||||||
m_customId = ui->customIdEdit->text();
|
m_customId = ui->customIdEdit->text();
|
||||||
|
@@ -40,10 +40,7 @@ class AnnotationEditorDialog : public QDialog
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum EditorMode { ItemAnnotation, GlobalAnnotation };
|
explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation);
|
||||||
|
|
||||||
explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation,
|
|
||||||
EditorMode mode = EditorMode::ItemAnnotation);
|
|
||||||
~AnnotationEditorDialog();
|
~AnnotationEditorDialog();
|
||||||
|
|
||||||
void setAnnotation(const Annotation &annotation);
|
void setAnnotation(const Annotation &annotation);
|
||||||
@@ -52,9 +49,6 @@ public:
|
|||||||
void setCustomId(const QString &customId);
|
void setCustomId(const QString &customId);
|
||||||
QString customId() const;
|
QString customId() const;
|
||||||
|
|
||||||
void changeEditorMode(EditorMode mode);
|
|
||||||
EditorMode editorMode() const;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void accepted();
|
void accepted();
|
||||||
|
|
||||||
@@ -75,14 +69,11 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const QString annotationEditorTitle = {tr("Annotation Editor")};
|
const QString annotationEditorTitle = {tr("Annotation Editor")};
|
||||||
const QString globalEditorTitle = {tr("Global Annotation Editor")};
|
|
||||||
const QString defaultTabName = {tr("Annotation")};
|
const QString defaultTabName = {tr("Annotation")};
|
||||||
Ui::AnnotationEditorDialog *ui;
|
Ui::AnnotationEditorDialog *ui;
|
||||||
|
|
||||||
QString m_customId;
|
QString m_customId;
|
||||||
Annotation m_annotation;
|
Annotation m_annotation;
|
||||||
|
|
||||||
EditorMode m_editorMode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} //namespace QmlDesigner
|
} //namespace QmlDesigner
|
||||||
|
@@ -6,15 +6,16 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1100</width>
|
<width>1344</width>
|
||||||
<height>600</height>
|
<height>819</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string notr="true">Dialog</string>
|
<string notr="true">Dialog</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
|
<widget class="QWidget" name="annotationContainer" native="true">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="targetIdLayout">
|
<layout class="QHBoxLayout" name="targetIdLayout">
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#include "globalannotationeditor.h"
|
#include "globalannotationeditor.h"
|
||||||
|
|
||||||
#include "annotationeditordialog.h"
|
#include "globalannotationeditordialog.h"
|
||||||
#include "annotation.h"
|
#include "annotation.h"
|
||||||
|
|
||||||
#include "qmlmodelnodeproxy.h"
|
#include "qmlmodelnodeproxy.h"
|
||||||
@@ -49,15 +49,13 @@ GlobalAnnotationEditor::~GlobalAnnotationEditor()
|
|||||||
|
|
||||||
void GlobalAnnotationEditor::showWidget()
|
void GlobalAnnotationEditor::showWidget()
|
||||||
{
|
{
|
||||||
m_dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(),
|
m_dialog = new GlobalAnnotationEditorDialog(Core::ICore::dialogParent(),
|
||||||
modelNode().validId(),
|
|
||||||
"",
|
|
||||||
modelNode().globalAnnotation(),
|
modelNode().globalAnnotation(),
|
||||||
AnnotationEditorDialog::EditorMode::GlobalAnnotation);
|
modelNode().globalStatus());
|
||||||
|
|
||||||
QObject::connect(m_dialog, &AnnotationEditorDialog::accepted,
|
QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::accepted,
|
||||||
this, &GlobalAnnotationEditor::acceptedClicked);
|
this, &GlobalAnnotationEditor::acceptedClicked);
|
||||||
QObject::connect(m_dialog, &AnnotationEditorDialog::rejected,
|
QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::rejected,
|
||||||
this, &GlobalAnnotationEditor::cancelClicked);
|
this, &GlobalAnnotationEditor::cancelClicked);
|
||||||
|
|
||||||
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
|
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
@@ -121,12 +119,24 @@ void GlobalAnnotationEditor::removeFullAnnotation()
|
|||||||
void GlobalAnnotationEditor::acceptedClicked()
|
void GlobalAnnotationEditor::acceptedClicked()
|
||||||
{
|
{
|
||||||
if (m_dialog) {
|
if (m_dialog) {
|
||||||
|
|
||||||
Annotation annotation = m_dialog->annotation();
|
Annotation annotation = m_dialog->annotation();
|
||||||
|
|
||||||
if (annotation.comments().isEmpty())
|
if (annotation.comments().isEmpty())
|
||||||
m_modelNode.removeGlobalAnnotation();
|
m_modelNode.removeGlobalAnnotation();
|
||||||
else
|
else
|
||||||
m_modelNode.setGlobalAnnotation(annotation);
|
m_modelNode.setGlobalAnnotation(annotation);
|
||||||
|
|
||||||
|
GlobalAnnotationStatus status = m_dialog->globalStatus();
|
||||||
|
|
||||||
|
if (status.status() == GlobalAnnotationStatus::NoStatus) {
|
||||||
|
if (m_modelNode.hasGlobalStatus()) {
|
||||||
|
m_modelNode.removeGlobalStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_modelNode.setGlobalStatus(status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hideWidget();
|
hideWidget();
|
||||||
|
@@ -29,7 +29,7 @@
|
|||||||
#include <QtQml>
|
#include <QtQml>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
#include "annotationeditordialog.h"
|
#include "globalannotationeditordialog.h"
|
||||||
#include "annotation.h"
|
#include "annotation.h"
|
||||||
|
|
||||||
#include "modelnode.h"
|
#include "modelnode.h"
|
||||||
@@ -67,7 +67,7 @@ private slots:
|
|||||||
void cancelClicked();
|
void cancelClicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPointer<AnnotationEditorDialog> m_dialog;
|
QPointer<GlobalAnnotationEditorDialog> m_dialog;
|
||||||
|
|
||||||
ModelNode m_modelNode;
|
ModelNode m_modelNode;
|
||||||
};
|
};
|
||||||
|
@@ -0,0 +1,268 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "globalannotationeditordialog.h"
|
||||||
|
#include "ui_globalannotationeditordialog.h"
|
||||||
|
#include "annotation.h"
|
||||||
|
#include "annotationcommenttab.h"
|
||||||
|
|
||||||
|
#include "ui_annotationcommenttab.h"
|
||||||
|
|
||||||
|
#include <timelineicons.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QToolBar>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
GlobalAnnotationEditorDialog::GlobalAnnotationEditorDialog(QWidget *parent, const Annotation &annotation, GlobalAnnotationStatus status)
|
||||||
|
: QDialog(parent)
|
||||||
|
, ui(new Ui::GlobalAnnotationEditorDialog)
|
||||||
|
, m_annotation(annotation)
|
||||||
|
, m_globalStatus(status)
|
||||||
|
, m_statusIsActive(false)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
setWindowFlag(Qt::Tool, true);
|
||||||
|
setModal(true);
|
||||||
|
|
||||||
|
connect(this, &QDialog::accepted, this, &GlobalAnnotationEditorDialog::acceptedClicked);
|
||||||
|
|
||||||
|
connect(ui->tabWidget, &QTabWidget::currentChanged, this, &GlobalAnnotationEditorDialog::tabChanged);
|
||||||
|
|
||||||
|
auto *commentCornerWidget = new QToolBar;
|
||||||
|
|
||||||
|
auto *commentAddAction = new QAction(TimelineIcons::ADD_TIMELINE.icon(), tr("Add Comment")); //timeline icons?
|
||||||
|
auto *commentRemoveAction = new QAction(TimelineIcons::REMOVE_TIMELINE.icon(),
|
||||||
|
tr("Remove Comment")); //timeline icons?
|
||||||
|
|
||||||
|
connect(commentAddAction, &QAction::triggered, this, [this]() {
|
||||||
|
addComment(Comment());
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(commentRemoveAction, &QAction::triggered, this, [this]() {
|
||||||
|
|
||||||
|
if (ui->tabWidget->count() == 0) { //it is not even supposed to happen but lets be sure
|
||||||
|
QTC_ASSERT(false, return);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentIndex = ui->tabWidget->currentIndex();
|
||||||
|
QString currentTitle = ui->tabWidget->tabText(currentIndex);
|
||||||
|
|
||||||
|
QMessageBox *deleteDialog = new QMessageBox(this);
|
||||||
|
deleteDialog->setWindowTitle(currentTitle);
|
||||||
|
deleteDialog->setText(tr("Delete this comment?"));
|
||||||
|
deleteDialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||||
|
deleteDialog->setDefaultButton(QMessageBox::Yes);
|
||||||
|
|
||||||
|
int result = deleteDialog->exec();
|
||||||
|
|
||||||
|
if (result == QMessageBox::Yes) {
|
||||||
|
removeComment(currentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui->tabWidget->count() == 0) //lets be sure that tabWidget is never empty
|
||||||
|
addComment(Comment());
|
||||||
|
});
|
||||||
|
|
||||||
|
commentCornerWidget->addAction(commentAddAction);
|
||||||
|
commentCornerWidget->addAction(commentRemoveAction);
|
||||||
|
|
||||||
|
ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner);
|
||||||
|
|
||||||
|
connect(ui->statusAddButton, &QPushButton::clicked, [&](bool){
|
||||||
|
setStatusVisibility(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
setStatus(m_globalStatus);
|
||||||
|
|
||||||
|
fillFields();
|
||||||
|
setWindowTitle(globalEditorTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalAnnotationEditorDialog::~GlobalAnnotationEditorDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::setAnnotation(const Annotation &annotation)
|
||||||
|
{
|
||||||
|
m_annotation = annotation;
|
||||||
|
fillFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
Annotation GlobalAnnotationEditorDialog::annotation() const
|
||||||
|
{
|
||||||
|
return m_annotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::setStatus(GlobalAnnotationStatus status)
|
||||||
|
{
|
||||||
|
m_globalStatus = status;
|
||||||
|
|
||||||
|
bool hasStatus = (status.status() != GlobalAnnotationStatus::NoStatus);
|
||||||
|
|
||||||
|
if (hasStatus) {
|
||||||
|
ui->statusComboBox->setCurrentIndex(int(status.status()));
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatusVisibility(hasStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalAnnotationStatus GlobalAnnotationEditorDialog::globalStatus() const
|
||||||
|
{
|
||||||
|
return m_globalStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::acceptedClicked()
|
||||||
|
{
|
||||||
|
Annotation annotation;
|
||||||
|
|
||||||
|
annotation.removeComments();
|
||||||
|
|
||||||
|
for (int i = 0; i < ui->tabWidget->count(); i++) {
|
||||||
|
AnnotationCommentTab* tab = reinterpret_cast<AnnotationCommentTab*>(ui->tabWidget->widget(i));
|
||||||
|
if (!tab)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Comment comment = tab->currentComment();
|
||||||
|
|
||||||
|
if (!comment.isEmpty())
|
||||||
|
annotation.addComment(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_annotation = annotation;
|
||||||
|
|
||||||
|
if (m_statusIsActive) {
|
||||||
|
m_globalStatus.setStatus(ui->statusComboBox->currentIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
emit GlobalAnnotationEditorDialog::accepted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::commentTitleChanged(const QString &text, QWidget *tab)
|
||||||
|
{
|
||||||
|
int tabIndex = ui->tabWidget->indexOf(tab);
|
||||||
|
if (tabIndex >= 0)
|
||||||
|
ui->tabWidget->setTabText(tabIndex, text);
|
||||||
|
|
||||||
|
if (text.isEmpty())
|
||||||
|
ui->tabWidget->setTabText(tabIndex,
|
||||||
|
(defaultTabName + " " + QString::number(tabIndex+1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::fillFields()
|
||||||
|
{
|
||||||
|
setupComments();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::setupComments()
|
||||||
|
{
|
||||||
|
ui->tabWidget->setUpdatesEnabled(false);
|
||||||
|
|
||||||
|
deleteAllTabs();
|
||||||
|
|
||||||
|
const QVector<Comment> comments = m_annotation.comments();
|
||||||
|
|
||||||
|
if (comments.isEmpty())
|
||||||
|
addComment(Comment());
|
||||||
|
|
||||||
|
for (const Comment &comment : comments) {
|
||||||
|
addCommentTab(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->tabWidget->setUpdatesEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::addComment(const Comment &comment)
|
||||||
|
{
|
||||||
|
m_annotation.addComment(comment);
|
||||||
|
addCommentTab(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::removeComment(int index)
|
||||||
|
{
|
||||||
|
if ((m_annotation.commentsSize() > index) && (index >= 0)) {
|
||||||
|
m_annotation.removeComment(index);
|
||||||
|
removeCommentTab(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::addCommentTab(const Comment &comment)
|
||||||
|
{
|
||||||
|
auto commentTab = new AnnotationCommentTab();
|
||||||
|
commentTab->setComment(comment);
|
||||||
|
|
||||||
|
QString tabTitle(comment.title());
|
||||||
|
int tabIndex = ui->tabWidget->addTab(commentTab, tabTitle);
|
||||||
|
ui->tabWidget->setCurrentIndex(tabIndex);
|
||||||
|
|
||||||
|
if (tabTitle.isEmpty()) {
|
||||||
|
const QString appendix = ((tabIndex > 0) ? QString::number(tabIndex+1) : "");
|
||||||
|
|
||||||
|
tabTitle = QString("%1 %2").arg(defaultTabName).arg(appendix);
|
||||||
|
|
||||||
|
ui->tabWidget->setTabText(tabIndex, tabTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(commentTab, &AnnotationCommentTab::titleChanged,
|
||||||
|
this, &GlobalAnnotationEditorDialog::commentTitleChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::removeCommentTab(int index)
|
||||||
|
{
|
||||||
|
if ((ui->tabWidget->count() > index) && (index >= 0)) {
|
||||||
|
ui->tabWidget->removeTab(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::deleteAllTabs()
|
||||||
|
{
|
||||||
|
while (ui->tabWidget->count() > 0) {
|
||||||
|
QWidget *w = ui->tabWidget->widget(0);
|
||||||
|
ui->tabWidget->removeTab(0);
|
||||||
|
delete w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::setStatusVisibility(bool hasStatus)
|
||||||
|
{
|
||||||
|
ui->statusAddButton->setVisible(!hasStatus);
|
||||||
|
ui->statusComboBox->setVisible(hasStatus);
|
||||||
|
|
||||||
|
m_statusIsActive = hasStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalAnnotationEditorDialog::tabChanged(int index)
|
||||||
|
{
|
||||||
|
(void) index;
|
||||||
|
}
|
||||||
|
|
||||||
|
} //namespace QmlDesigner
|
@@ -0,0 +1,82 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
#include "annotation.h"
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class GlobalAnnotationEditorDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GlobalAnnotationEditorDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit GlobalAnnotationEditorDialog(QWidget *parent, const Annotation &annotation, GlobalAnnotationStatus status);
|
||||||
|
~GlobalAnnotationEditorDialog();
|
||||||
|
|
||||||
|
void setAnnotation(const Annotation &annotation);
|
||||||
|
Annotation annotation() const;
|
||||||
|
|
||||||
|
void setStatus(GlobalAnnotationStatus status);
|
||||||
|
GlobalAnnotationStatus globalStatus() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void accepted();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void acceptedClicked();
|
||||||
|
void tabChanged(int index);
|
||||||
|
void commentTitleChanged(const QString &text, QWidget *tab);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void fillFields();
|
||||||
|
void setupComments();
|
||||||
|
void addComment(const Comment &comment);
|
||||||
|
void removeComment(int index);
|
||||||
|
|
||||||
|
void addCommentTab(const Comment &comment);
|
||||||
|
void removeCommentTab(int index);
|
||||||
|
void deleteAllTabs();
|
||||||
|
|
||||||
|
void setStatusVisibility(bool hasStatus);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const QString globalEditorTitle = {tr("Global Annotation Editor")};
|
||||||
|
const QString defaultTabName = {tr("Annotation")};
|
||||||
|
Ui::GlobalAnnotationEditorDialog *ui;
|
||||||
|
|
||||||
|
Annotation m_annotation;
|
||||||
|
GlobalAnnotationStatus m_globalStatus;
|
||||||
|
bool m_statusIsActive;
|
||||||
|
};
|
||||||
|
|
||||||
|
} //namespace QmlDesigner
|
@@ -0,0 +1,165 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>QmlDesigner::GlobalAnnotationEditorDialog</class>
|
||||||
|
<widget class="QDialog" name="QmlDesigner::GlobalAnnotationEditorDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1344</width>
|
||||||
|
<height>819</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string notr="true">Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="statusContainer" native="true">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<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="QPushButton" name="statusAddButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add Status</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="statusComboBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>In Progress</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>In Review</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Done</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</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>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="movable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Tab 1</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_2">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Tab 2</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::StrongFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>tabWidget</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>QmlDesigner::GlobalAnnotationEditorDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>261</x>
|
||||||
|
<y>473</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>QmlDesigner::GlobalAnnotationEditorDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>329</x>
|
||||||
|
<y>473</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|