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.
|
||||
(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
|
||||
|
||||
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}
|
||||
\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
|
||||
in \QC.\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
|
||||
\li \l{DirectionalLight}{Light Directional}
|
||||
\li \l{PointLight}{Light Point}
|
||||
\li \l{SpotLight}{Light Spot}
|
||||
\li \l{AreaLight}{Light Area}
|
||||
\endlist
|
||||
|
||||
@@ -121,6 +122,22 @@
|
||||
Aside from fade, a point light has the same properties as a directional
|
||||
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
|
||||
|
||||
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
|
||||
colors using two different area lights.
|
||||
|
||||
\image area-light.png
|
||||
\image studio-3d-area-light.png
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
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/
|
||||
|
||||
HEADERS += $$PWD/synchronizecommand.h
|
||||
HEADERS += $$PWD/changepreviewimagesizecommand.h
|
||||
HEADERS += $$PWD/changelanguagecommand.h
|
||||
HEADERS += $$PWD//debugoutputcommand.h
|
||||
HEADERS += $$PWD/endpuppetcommand.h
|
||||
HEADERS += $$PWD/tokencommand.h
|
||||
@@ -33,6 +35,8 @@ HEADERS += $$PWD/inputeventcommand.h
|
||||
HEADERS += $$PWD/view3dactioncommand.h
|
||||
|
||||
SOURCES += $$PWD/synchronizecommand.cpp
|
||||
SOURCES += $$PWD/changepreviewimagesizecommand.cpp
|
||||
SOURCES += $$PWD/changelanguagecommand.cpp
|
||||
SOURCES += $$PWD/debugoutputcommand.cpp
|
||||
SOURCES += $$PWD/endpuppetcommand.cpp
|
||||
SOURCES += $$PWD/tokencommand.cpp
|
||||
|
@@ -35,43 +35,44 @@
|
||||
|
||||
#include "nodeinstanceserverinterface.h"
|
||||
|
||||
#include "propertyabstractcontainer.h"
|
||||
#include "propertyvaluecontainer.h"
|
||||
#include "propertybindingcontainer.h"
|
||||
#include "instancecontainer.h"
|
||||
#include "changeauxiliarycommand.h"
|
||||
#include "changebindingscommand.h"
|
||||
#include "changefileurlcommand.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 "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 "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 "changeselectioncommand.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 {
|
||||
|
||||
@@ -91,7 +92,7 @@ NodeInstanceClientProxy::NodeInstanceClientProxy(QObject *parent)
|
||||
m_synchronizeId(-1)
|
||||
{
|
||||
connect(&m_puppetAliveTimer, &QTimer::timeout, this, &NodeInstanceClientProxy::sendPuppetAliveCommand);
|
||||
m_puppetAliveTimer.setInterval(1000);
|
||||
m_puppetAliveTimer.setInterval(2000);
|
||||
m_puppetAliveTimer.start();
|
||||
}
|
||||
|
||||
@@ -324,6 +325,16 @@ void NodeInstanceClientProxy::view3DAction(const View3DActionCommand &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()
|
||||
{
|
||||
QList<QVariant> commandList;
|
||||
@@ -490,6 +501,9 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command)
|
||||
static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand");
|
||||
static const int inputEventCommandType = QMetaType::type("InputEventCommand");
|
||||
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();
|
||||
|
||||
@@ -539,6 +553,10 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command)
|
||||
} else if (commandType == changeSelectionCommandType) {
|
||||
ChangeSelectionCommand changeSelectionCommand = command.value<ChangeSelectionCommand>();
|
||||
changeSelection(changeSelectionCommand);
|
||||
} else if (command.userType() == changeLanguageCommand) {
|
||||
changeLanguage(command.value<ChangeLanguageCommand>());
|
||||
} else if (command.userType() == changePreviewImageSizeCommand) {
|
||||
changePreviewImageSize(command.value<ChangePreviewImageSizeCommand>());
|
||||
} else {
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
@@ -61,6 +61,8 @@ class ChangeSelectionCommand;
|
||||
class PuppetToCreatorCommand;
|
||||
class InputEventCommand;
|
||||
class View3DActionCommand;
|
||||
class ChangeLanguageCommand;
|
||||
class ChangePreviewImageSizeCommand;
|
||||
|
||||
class NodeInstanceClientProxy : public QObject, public NodeInstanceClientInterface
|
||||
{
|
||||
@@ -116,6 +118,8 @@ protected:
|
||||
static QVariant readCommandFromIOStream(QIODevice *ioDevice, quint32 *readCommandCounter, quint32 *blockSize);
|
||||
void inputEvent(const InputEventCommand &command);
|
||||
void view3DAction(const View3DActionCommand &command);
|
||||
void changeLanguage(const ChangeLanguageCommand &command);
|
||||
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command);
|
||||
|
||||
protected slots:
|
||||
void readDataStream();
|
||||
|
@@ -26,44 +26,45 @@
|
||||
#include "nodeinstanceserverinterface.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 "changeauxiliarycommand.h"
|
||||
#include "changebindingscommand.h"
|
||||
#include "changefileurlcommand.h"
|
||||
#include "changeidscommand.h"
|
||||
#include "changelanguagecommand.h"
|
||||
#include "changenodesourcecommand.h"
|
||||
#include "changeselectioncommand.h"
|
||||
#include "inputeventcommand.h"
|
||||
#include "view3dactioncommand.h"
|
||||
|
||||
#include "informationchangedcommand.h"
|
||||
#include "pixmapchangedcommand.h"
|
||||
#include "valueschangedcommand.h"
|
||||
#include "changestatecommand.h"
|
||||
#include "changevaluescommand.h"
|
||||
#include "changepreviewimagesizecommand.h"
|
||||
#include "childrenchangedcommand.h"
|
||||
#include "imagecontainer.h"
|
||||
#include "statepreviewimagechangedcommand.h"
|
||||
#include "clearscenecommand.h"
|
||||
#include "completecomponentcommand.h"
|
||||
#include "componentcompletedcommand.h"
|
||||
#include "synchronizecommand.h"
|
||||
#include "tokencommand.h"
|
||||
#include "removesharedmemorycommand.h"
|
||||
#include "endpuppetcommand.h"
|
||||
#include "createinstancescommand.h"
|
||||
#include "createscenecommand.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 "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>
|
||||
|
||||
@@ -212,6 +213,12 @@ void NodeInstanceServerInterface::registerCommands()
|
||||
|
||||
qRegisterMetaType<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 InputEventCommand;
|
||||
class View3DActionCommand;
|
||||
class ChangeLanguageCommand;
|
||||
class ChangePreviewImageSizeCommand;
|
||||
|
||||
class NodeInstanceServerInterface : public QObject
|
||||
{
|
||||
@@ -85,9 +87,10 @@ public:
|
||||
virtual void changeSelection(const ChangeSelectionCommand &command) = 0;
|
||||
virtual void inputEvent(const InputEventCommand &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();
|
||||
};
|
||||
|
@@ -69,6 +69,7 @@
|
||||
#include <changeselectioncommand.h>
|
||||
#include <inputeventcommand.h>
|
||||
#include <view3dactioncommand.h>
|
||||
#include <changelanguagecommand.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QQmlEngine>
|
||||
@@ -1397,7 +1398,22 @@ void NodeInstanceServer::view3DAction(const View3DActionCommand &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
|
||||
|
||||
#include <QDebug>
|
||||
#include <QUrl>
|
||||
#include <QVector>
|
||||
#include <QSet>
|
||||
#include <QStringList>
|
||||
#include <QPointer>
|
||||
|
||||
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
|
||||
#include <multilanguagelink.h>
|
||||
#endif
|
||||
|
||||
#include <QTranslator>
|
||||
#include <memory>
|
||||
|
||||
#include <nodeinstanceserverinterface.h>
|
||||
#include "servernodeinstance.h"
|
||||
#include "debugoutputcommand.h"
|
||||
@@ -47,6 +55,37 @@ QList<T>toList(const QSet<T> &set)
|
||||
}
|
||||
} //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
|
||||
class QFileSystemWatcher;
|
||||
class QQmlView;
|
||||
@@ -112,6 +151,8 @@ public:
|
||||
void changeSelection(const ChangeSelectionCommand &command) override;
|
||||
void inputEvent(const InputEventCommand &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;
|
||||
bool hasInstanceForId(qint32 id) const;
|
||||
@@ -248,6 +289,7 @@ private:
|
||||
QPointer<QObject> m_dummyContextObject;
|
||||
QPointer<QQmlComponent> m_importComponent;
|
||||
QPointer<QObject> m_importComponentObject;
|
||||
std::unique_ptr<MultiLanguage::Link> multilanguageLink;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -768,6 +768,8 @@ QObject *ObjectNodeInstance::createComponent(const QString &componentPath, QQmlC
|
||||
qWarning() << error;
|
||||
}
|
||||
|
||||
object->setProperty("__designer_url__", QUrl::fromLocalFile(componentPath));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
@@ -25,10 +25,12 @@
|
||||
|
||||
#include "qt5previewnodeinstanceserver.h"
|
||||
|
||||
#include "nodeinstanceclientinterface.h"
|
||||
#include "statepreviewimagechangedcommand.h"
|
||||
#include "changepreviewimagesizecommand.h"
|
||||
#include "createscenecommand.h"
|
||||
#include "nodeinstanceclientinterface.h"
|
||||
#include "removesharedmemorycommand.h"
|
||||
#include "statepreviewimagechangedcommand.h"
|
||||
|
||||
#include <QQuickView>
|
||||
#include <QQuickItem>
|
||||
#include <designersupportdelegate.h>
|
||||
@@ -100,7 +102,9 @@ QImage Qt5PreviewNodeInstanceServer::renderPreviewImage()
|
||||
QRectF boundingRect = rootNodeInstance().boundingRect();
|
||||
|
||||
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);
|
||||
|
||||
@@ -113,4 +117,15 @@ void QmlDesigner::Qt5PreviewNodeInstanceServer::removeSharedMemory(const QmlDesi
|
||||
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
|
||||
|
@@ -38,6 +38,7 @@ public:
|
||||
void createScene(const CreateSceneCommand &command) override;
|
||||
void changeState(const ChangeStateCommand &command) override;
|
||||
void removeSharedMemory(const RemoveSharedMemoryCommand &command) override;
|
||||
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override;
|
||||
|
||||
QImage renderPreviewImage();
|
||||
|
||||
@@ -47,6 +48,7 @@ protected:
|
||||
|
||||
private:
|
||||
ServerNodeInstance m_currentState;
|
||||
QSize m_previewSize{160, 160};
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -5,6 +5,13 @@ CONFIG += c++11
|
||||
|
||||
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 (../instances/instances.pri)
|
||||
include (instances/instances.pri)
|
||||
|
@@ -26,6 +26,8 @@
|
||||
import HelperWidgets 2.0
|
||||
import QtQuick 2.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import StudioTheme 1.0 as StudioTheme
|
||||
|
||||
Section {
|
||||
id: section
|
||||
caption: qsTr("Animation")
|
||||
@@ -33,6 +35,7 @@ Section {
|
||||
anchors.right: parent.right
|
||||
|
||||
property bool showDuration: true
|
||||
property bool showEasingCurve: false
|
||||
|
||||
SectionLayout {
|
||||
Label {
|
||||
@@ -100,5 +103,22 @@ Section {
|
||||
text: backendValues.alwaysRunToEnd.valueToString
|
||||
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 {
|
||||
showEasingCurve: true
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -325,13 +325,11 @@ Rectangle {
|
||||
frameVisible: false
|
||||
|
||||
id: tabView
|
||||
height: Math.max(layoutSectionHeight, specficsHeight)
|
||||
height: Math.max(layoutSectionHeight, specficsHeight, advancedHeight) + extraHeight
|
||||
|
||||
property int layoutSectionHeight: 400
|
||||
property int specficsOneHeight: 0
|
||||
property int specficsTwoHeight: 0
|
||||
|
||||
property int specficsHeight: Math.max(specficsOneHeight, specficsTwoHeight)
|
||||
property int advancedHeight: 0
|
||||
property int layoutSectionHeight: 0
|
||||
property int specficsHeight: 0
|
||||
|
||||
property int extraHeight: 40
|
||||
|
||||
@@ -341,6 +339,9 @@ Rectangle {
|
||||
component: Column {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
onImplicitHeightChanged: tabView.specficsHeight = implicitHeight
|
||||
|
||||
Loader {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
@@ -355,13 +356,6 @@ Rectangle {
|
||||
active = false
|
||||
active = true
|
||||
}
|
||||
|
||||
property int loaderHeight: specificsTwo.item.height + tabView.extraHeight
|
||||
onLoaderHeightChanged: tabView.specficsTwoHeight = loaderHeight
|
||||
|
||||
onLoaded: {
|
||||
tabView.specficsTwoHeight = loaderHeight
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -387,11 +381,9 @@ Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
onImplicitHeightChanged: tabView.layoutSectionHeight = implicitHeight
|
||||
|
||||
LayoutSection {
|
||||
property int childRectHeight: childrenRect.height
|
||||
onChildRectHeightChanged: {
|
||||
tabView.layoutSectionHeight = childRectHeight + tabView.extraHeight
|
||||
}
|
||||
}
|
||||
|
||||
MarginSection {
|
||||
@@ -720,6 +712,9 @@ Rectangle {
|
||||
component: Column {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
onImplicitHeightChanged: tabView.advancedHeight = implicitHeight
|
||||
|
||||
AdvancedSection {
|
||||
}
|
||||
LayerSection {
|
||||
|
@@ -79,6 +79,7 @@ Column {
|
||||
}
|
||||
|
||||
AnimationSection {
|
||||
showEasingCurve: true
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -35,6 +35,7 @@ Column {
|
||||
}
|
||||
|
||||
AnimationSection {
|
||||
showEasingCurve: true
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -163,4 +163,9 @@ StudioControls.ComboBox {
|
||||
colorLogic.invalidate()
|
||||
comboBox.__isCompleted = true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: modelNodeBackend
|
||||
onSelectionToBeChanged: comboBox.popup.close()
|
||||
}
|
||||
}
|
||||
|
@@ -193,7 +193,7 @@ Section {
|
||||
Layout.fillWidth: true
|
||||
backendValue: getBackendValue("styleName")
|
||||
model: styleNamesForFamily(fontComboBox.familyName)
|
||||
useString: true
|
||||
valueType: ComboBox.String
|
||||
}
|
||||
|
||||
Label {
|
||||
|
@@ -36,9 +36,11 @@ ButtonRow {
|
||||
property alias checked: myAbstractButton.checked
|
||||
|
||||
signal onCheckedChanged()
|
||||
signal clicked
|
||||
|
||||
AbstractButton {
|
||||
id: myAbstractButton
|
||||
onCheckedChanged: myButtonRow.onCheckedChanged()
|
||||
onClicked: myButtonRow.clicked()
|
||||
}
|
||||
}
|
||||
|
@@ -48,67 +48,73 @@ QtObject {
|
||||
readonly property string adsClose: "\u0029"
|
||||
readonly property string adsDetach: "\u002A"
|
||||
readonly property string adsDropDown: "\u002B"
|
||||
readonly property string alignBottom: "\u002C"
|
||||
readonly property string alignCenterHorizontal: "\u002D"
|
||||
readonly property string alignCenterVertical: "\u002E"
|
||||
readonly property string alignLeft: "\u002F"
|
||||
readonly property string alignRight: "\u0030"
|
||||
readonly property string alignTo: "\u0031"
|
||||
readonly property string alignTop: "\u0032"
|
||||
readonly property string anchorBaseline: "\u0033"
|
||||
readonly property string anchorBottom: "\u0034"
|
||||
readonly property string anchorFill: "\u0035"
|
||||
readonly property string anchorLeft: "\u0036"
|
||||
readonly property string anchorRight: "\u0037"
|
||||
readonly property string anchorTop: "\u0038"
|
||||
readonly property string annotationBubble: "\u0039"
|
||||
readonly property string annotationDecal: "\u003A"
|
||||
readonly property string centerHorizontal: "\u003B"
|
||||
readonly property string centerVertical: "\u003C"
|
||||
readonly property string closeCross: "\u003D"
|
||||
readonly property string decisionNode: "\u003E"
|
||||
readonly property string deleteColumn: "\u003F"
|
||||
readonly property string deleteRow: "\u0040"
|
||||
readonly property string deleteTable: "\u0041"
|
||||
readonly property string detach: "\u0042"
|
||||
readonly property string distributeBottom: "\u0043"
|
||||
readonly property string distributeCenterHorizontal: "\u0044"
|
||||
readonly property string distributeCenterVertical: "\u0045"
|
||||
readonly property string distributeLeft: "\u0046"
|
||||
readonly property string distributeOriginBottomRight: "\u0047"
|
||||
readonly property string distributeOriginCenter: "\u0048"
|
||||
readonly property string distributeOriginNone: "\u0049"
|
||||
readonly property string distributeOriginTopLeft: "\u004A"
|
||||
readonly property string distributeRight: "\u004B"
|
||||
readonly property string distributeSpacingHorizontal: "\u004C"
|
||||
readonly property string distributeSpacingVertical: "\u004D"
|
||||
readonly property string distributeTop: "\u004E"
|
||||
readonly property string edit: "\u004F"
|
||||
readonly property string fontStyleBold: "\u0050"
|
||||
readonly property string fontStyleItalic: "\u0051"
|
||||
readonly property string fontStyleStrikethrough: "\u0052"
|
||||
readonly property string fontStyleUnderline: "\u0053"
|
||||
readonly property string mergeCells: "\u0054"
|
||||
readonly property string redo: "\u0055"
|
||||
readonly property string splitColumns: "\u0056"
|
||||
readonly property string splitRows: "\u0057"
|
||||
readonly property string startNode: "\u0058"
|
||||
readonly property string testIcon: "\u0059"
|
||||
readonly property string textAlignBottom: "\u005A"
|
||||
readonly property string textAlignCenter: "\u005B"
|
||||
readonly property string textAlignLeft: "\u005C"
|
||||
readonly property string textAlignMiddle: "\u005D"
|
||||
readonly property string textAlignRight: "\u005E"
|
||||
readonly property string textAlignTop: "\u005F"
|
||||
readonly property string textBulletList: "\u0060"
|
||||
readonly property string textFullJustification: "\u0061"
|
||||
readonly property string textNumberedList: "\u0062"
|
||||
readonly property string tickIcon: "\u0063"
|
||||
readonly property string triState: "\u0064"
|
||||
readonly property string undo: "\u0065"
|
||||
readonly property string upDownIcon: "\u0066"
|
||||
readonly property string upDownSquare2: "\u0067"
|
||||
readonly property string wildcard: "\u0068"
|
||||
readonly property string aliasAnimated: "\u002C"
|
||||
readonly property string aliasProperty: "\u002D"
|
||||
readonly property string alignBottom: "\u002E"
|
||||
readonly property string alignCenterHorizontal: "\u002F"
|
||||
readonly property string alignCenterVertical: "\u0030"
|
||||
readonly property string alignLeft: "\u0031"
|
||||
readonly property string alignRight: "\u0032"
|
||||
readonly property string alignTo: "\u0033"
|
||||
readonly property string alignTop: "\u0034"
|
||||
readonly property string anchorBaseline: "\u0035"
|
||||
readonly property string anchorBottom: "\u0036"
|
||||
readonly property string anchorFill: "\u0037"
|
||||
readonly property string anchorLeft: "\u0038"
|
||||
readonly property string anchorRight: "\u0039"
|
||||
readonly property string anchorTop: "\u003A"
|
||||
readonly property string animatedProperty: "\u003B"
|
||||
readonly property string annotationBubble: "\u003C"
|
||||
readonly property string annotationDecal: "\u003D"
|
||||
readonly property string assign: "\u003E"
|
||||
readonly property string centerHorizontal: "\u003F"
|
||||
readonly property string centerVertical: "\u0040"
|
||||
readonly property string closeCross: "\u0041"
|
||||
readonly property string curveDesigner: "\u0042"
|
||||
readonly property string curveEditor: "\u0043"
|
||||
readonly property string decisionNode: "\u0044"
|
||||
readonly property string deleteColumn: "\u0045"
|
||||
readonly property string deleteRow: "\u0046"
|
||||
readonly property string deleteTable: "\u0047"
|
||||
readonly property string detach: "\u0048"
|
||||
readonly property string distributeBottom: "\u0049"
|
||||
readonly property string distributeCenterHorizontal: "\u004A"
|
||||
readonly property string distributeCenterVertical: "\u004B"
|
||||
readonly property string distributeLeft: "\u004C"
|
||||
readonly property string distributeOriginBottomRight: "\u004D"
|
||||
readonly property string distributeOriginCenter: "\u004E"
|
||||
readonly property string distributeOriginNone: "\u004F"
|
||||
readonly property string distributeOriginTopLeft: "\u0050"
|
||||
readonly property string distributeRight: "\u0051"
|
||||
readonly property string distributeSpacingHorizontal: "\u0052"
|
||||
readonly property string distributeSpacingVertical: "\u0053"
|
||||
readonly property string distributeTop: "\u0054"
|
||||
readonly property string edit: "\u0055"
|
||||
readonly property string fontStyleBold: "\u0056"
|
||||
readonly property string fontStyleItalic: "\u0057"
|
||||
readonly property string fontStyleStrikethrough: "\u0058"
|
||||
readonly property string fontStyleUnderline: "\u0059"
|
||||
readonly property string mergeCells: "\u005A"
|
||||
readonly property string redo: "\u005B"
|
||||
readonly property string splitColumns: "\u005C"
|
||||
readonly property string splitRows: "\u005D"
|
||||
readonly property string startNode: "\u005E"
|
||||
readonly property string testIcon: "\u005F"
|
||||
readonly property string textAlignBottom: "\u0060"
|
||||
readonly property string textAlignCenter: "\u0061"
|
||||
readonly property string textAlignLeft: "\u0062"
|
||||
readonly property string textAlignMiddle: "\u0063"
|
||||
readonly property string textAlignRight: "\u0064"
|
||||
readonly property string textAlignTop: "\u0065"
|
||||
readonly property string textBulletList: "\u0066"
|
||||
readonly property string textFullJustification: "\u0067"
|
||||
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({
|
||||
"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 \
|
||||
$$PWD/sqlite3ext.h
|
||||
|
||||
SOURCES += $$PWD/sqlite3.c
|
||||
SOURCES += $$PWD/sqlite3.c \
|
||||
$$PWD/carray.c
|
||||
|
||||
gcc {
|
||||
QMAKE_CFLAGS_WARN_ON = -w
|
||||
|
18925
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 */
|
||||
int (*stmt_isexplain)(sqlite3_stmt*);
|
||||
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 */
|
||||
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
|
||||
/* Version 3.28.0 and later */
|
||||
#define sqlite3_stmt_isexplain sqlite3_api->isexplain
|
||||
#define sqlite3_value_frombind sqlite3_api->frombind
|
||||
#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
|
||||
#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) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
@@ -66,7 +66,7 @@ public:
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
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 &symbolNameColumn = table.addColumn("symbolName", Sqlite::ColumnType::Text);
|
||||
const Sqlite::Column &symbolKindColumn = table.addColumn("symbolKind", Sqlite::ColumnType::Integer);
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
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 &sourceNameColumn = table.addColumn("sourceName", Sqlite::ColumnType::Text);
|
||||
table.addUniqueIndex({directoryIdColumn, sourceNameColumn});
|
||||
@@ -113,7 +113,7 @@ public:
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
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);
|
||||
table.addUniqueIndex({directoryPathColumn});
|
||||
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
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);
|
||||
table.addColumn("toolChainArguments", Sqlite::ColumnType::Text);
|
||||
table.addColumn("compilerMacros", Sqlite::ColumnType::Text);
|
||||
@@ -160,7 +160,7 @@ public:
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
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 ¯oNameColumn = table.addColumn("macroName", Sqlite::ColumnType::Text);
|
||||
table.addIndex({sourceIdColumn, macroNameColumn});
|
||||
@@ -174,9 +174,7 @@ public:
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
table.setName("fileStatuses");
|
||||
table.addColumn("sourceId",
|
||||
Sqlite::ColumnType::Integer,
|
||||
Sqlite::Contraint::PrimaryKey);
|
||||
table.addColumn("sourceId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||
table.addColumn("size", Sqlite::ColumnType::Integer);
|
||||
table.addColumn("lastModified", Sqlite::ColumnType::Integer);
|
||||
table.addColumn("indexingTimeStamp", Sqlite::ColumnType::Integer);
|
||||
@@ -201,7 +199,7 @@ public:
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
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("projectPchBuildTime", Sqlite::ColumnType::Integer);
|
||||
table.addColumn("systemPchPath", Sqlite::ColumnType::Text);
|
||||
|
@@ -53,7 +53,7 @@ inline QString qmlDebugServices(QmlDebugServicesPreset preset)
|
||||
case QmlNativeDebuggerServices:
|
||||
return QStringLiteral("NativeQmlDebugger");
|
||||
case QmlPreviewServices:
|
||||
return QStringLiteral("QmlPreview");
|
||||
return QStringLiteral("QmlPreview,DebugTranslation");
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
return QString();
|
||||
|
@@ -942,6 +942,9 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
|
||||
if (checkTypeForDesignerSupport(typeId))
|
||||
addMessage(WarnUnsupportedTypeInVisualDesigner, typeErrorLocation, typeName);
|
||||
|
||||
if (QFileInfo(_doc->fileName()).baseName() == getRightMostIdentifier(typeId)->name.toString())
|
||||
addMessage(ErrTypeIsInstantiatedRecursively, typeErrorLocation, typeName);
|
||||
|
||||
if (checkTypeForQmlUiSupport(typeId))
|
||||
addMessage(ErrUnsupportedTypeInQmlUi, typeErrorLocation, typeName);
|
||||
|
||||
|
@@ -245,6 +245,8 @@ StaticAnalysisMessages::StaticAnalysisMessages()
|
||||
tr("Duplicate import (%1)."), 1);
|
||||
newMsg(ErrHitMaximumRecursion, Error,
|
||||
tr("Hit maximum recursion limit when visiting AST."));
|
||||
newMsg(ErrTypeIsInstantiatedRecursively, Error,
|
||||
tr("Type cannot be instantiated recursively (%1)."), 1);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
@@ -89,6 +89,7 @@ enum Type
|
||||
MaybeWarnEqualityTypeCoercion = 126,
|
||||
WarnConfusingExpressionStatement = 127,
|
||||
StateCannotHaveChildItem = 128,
|
||||
ErrTypeIsInstantiatedRecursively = 129,
|
||||
HintDeclarationsShouldBeAtStartOfFunction = 201,
|
||||
HintOneStatementPerLine = 202,
|
||||
WarnImperativeCodeNotEditableInVisualDesigner = 203,
|
||||
|
@@ -1,15 +1,26 @@
|
||||
add_qtc_library(Sqlite
|
||||
DEFINES
|
||||
SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS3_PARENTHESIS
|
||||
SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_COLUMN_METADATA
|
||||
PUBLIC_DEFINES
|
||||
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}
|
||||
PUBLIC_INCLUDES
|
||||
"${CMAKE_CURRENT_LIST_DIR}"
|
||||
../3rdparty/sqlite
|
||||
SOURCES
|
||||
../3rdparty/sqlite/sqlite3.c
|
||||
../3rdparty/sqlite/carray.c
|
||||
constraints.h
|
||||
createtablesqlstatementbuilder.cpp createtablesqlstatementbuilder.h
|
||||
lastchangedrowid.h
|
||||
sqlitebasestatement.cpp sqlitebasestatement.h
|
||||
sqlitecolumn.h
|
||||
sqlitedatabase.cpp sqlitedatabase.h
|
||||
@@ -19,6 +30,8 @@ add_qtc_library(Sqlite
|
||||
sqliteindex.h
|
||||
sqlitereadstatement.cpp sqlitereadstatement.h
|
||||
sqlitereadwritestatement.cpp sqlitereadwritestatement.h
|
||||
sqlitesessionchangeset.cpp sqlitesessionchangeset.h
|
||||
sqlitesessions.cpp sqlitesessions.h
|
||||
sqlitetable.h
|
||||
sqlitetransaction.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);
|
||||
}
|
||||
|
||||
void CreateTableSqlStatementBuilder::addColumn(Utils::SmallString &&columnName,
|
||||
void CreateTableSqlStatementBuilder::addColumn(Utils::SmallStringView columnName,
|
||||
ColumnType columnType,
|
||||
Contraint constraint)
|
||||
Constraints &&constraints)
|
||||
{
|
||||
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();
|
||||
|
||||
@@ -97,20 +107,162 @@ bool CreateTableSqlStatementBuilder::isValid() const
|
||||
return m_tableName.hasContent() && !m_columns.empty();
|
||||
}
|
||||
|
||||
void CreateTableSqlStatementBuilder::bindColumnDefinitions() const
|
||||
namespace {
|
||||
Utils::SmallStringView actionToText(ForeignKeyAction action)
|
||||
{
|
||||
Utils::SmallStringVector columnDefinitionStrings;
|
||||
|
||||
for (const Column &columns : m_columns) {
|
||||
Utils::SmallString columnDefinitionString = {columns.name(), " ", columns.typeString()};
|
||||
|
||||
switch (columns.constraint()) {
|
||||
case Contraint::PrimaryKey: columnDefinitionString.append(" PRIMARY KEY"); break;
|
||||
case Contraint::Unique: columnDefinitionString.append(" UNIQUE"); break;
|
||||
case Contraint::NoConstraint: break;
|
||||
switch (action) {
|
||||
case ForeignKeyAction::NoAction:
|
||||
return "NO ACTION";
|
||||
case ForeignKeyAction::Restrict:
|
||||
return "RESTRICT";
|
||||
case ForeignKeyAction::SetNull:
|
||||
return "SET NULL";
|
||||
case ForeignKeyAction::SetDefault:
|
||||
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);
|
||||
@@ -122,7 +274,7 @@ void CreateTableSqlStatementBuilder::bindAll() const
|
||||
|
||||
bindTemporary();
|
||||
bindIfNotExists();
|
||||
bindColumnDefinitions();
|
||||
bindColumnDefinitionsAndTableConstraints();
|
||||
bindWithoutRowId();
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "sqlitecolumn.h"
|
||||
#include "sqlstatementbuilder.h"
|
||||
#include "tableconstraints.h"
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
@@ -36,10 +37,13 @@ public:
|
||||
CreateTableSqlStatementBuilder();
|
||||
|
||||
void setTableName(Utils::SmallString &&tableName);
|
||||
void addColumn(Utils::SmallString &&columnName,
|
||||
|
||||
void addColumn(Utils::SmallStringView columnName,
|
||||
ColumnType columnType,
|
||||
Contraint constraint = Contraint::NoConstraint);
|
||||
void setColumns(const SqliteColumns &columns);
|
||||
Constraints &&constraints = {});
|
||||
void addConstraint(TableConstraint &&constraint);
|
||||
void setConstraints(TableConstraints constraints);
|
||||
void setColumns(SqliteColumns columns);
|
||||
void setUseWithoutRowId(bool useWithoutRowId);
|
||||
void setUseIfNotExists(bool useIfNotExists);
|
||||
void setUseTemporaryTable(bool useTemporaryTable);
|
||||
@@ -52,7 +56,7 @@ public:
|
||||
bool isValid() const;
|
||||
|
||||
protected:
|
||||
void bindColumnDefinitions() const;
|
||||
void bindColumnDefinitionsAndTableConstraints() const;
|
||||
void bindAll() const;
|
||||
void bindWithoutRowId() const;
|
||||
void bindIfNotExists() const;
|
||||
@@ -62,6 +66,7 @@ private:
|
||||
mutable SqlStatementBuilder m_sqlStatementBuilder;
|
||||
Utils::SmallString m_tableName;
|
||||
SqliteColumns m_columns;
|
||||
TableConstraints m_tableConstraints;
|
||||
bool m_useWithoutRowId = false;
|
||||
bool m_useIfNotExits = 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/sqlitereadstatement.cpp \
|
||||
$$PWD/sqlitereadwritestatement.cpp \
|
||||
$$PWD/sqlitesessionchangeset.cpp \
|
||||
$$PWD/sqlitesessions.cpp \
|
||||
$$PWD/sqlitewritestatement.cpp \
|
||||
$$PWD/sqlstatementbuilder.cpp \
|
||||
$$PWD/utf8string.cpp \
|
||||
@@ -24,13 +26,18 @@ SOURCES += \
|
||||
$$PWD/sqlitedatabase.cpp \
|
||||
$$PWD/sqlitebasestatement.cpp
|
||||
HEADERS += \
|
||||
$$PWD/constraints.h \
|
||||
$$PWD/tableconstraints.h \
|
||||
$$PWD/createtablesqlstatementbuilder.h \
|
||||
$$PWD/lastchangedrowid.h \
|
||||
$$PWD/sqlitedatabasebackend.h \
|
||||
$$PWD/sqlitedatabaseinterface.h \
|
||||
$$PWD/sqliteexception.h \
|
||||
$$PWD/sqliteglobal.h \
|
||||
$$PWD/sqlitereadstatement.h \
|
||||
$$PWD/sqlitereadwritestatement.h \
|
||||
$$PWD/sqlitesessionchangeset.h \
|
||||
$$PWD/sqlitesessions.h \
|
||||
$$PWD/sqlitetransaction.h \
|
||||
$$PWD/sqlitevalue.h \
|
||||
$$PWD/sqlitewritestatement.h \
|
||||
@@ -44,8 +51,18 @@ HEADERS += \
|
||||
$$PWD/sqliteindex.h \
|
||||
$$PWD/sqlitebasestatement.h
|
||||
|
||||
DEFINES += SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS3_PARENTHESIS \
|
||||
SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_COLUMN_METADATA SQLITE_ENABLE_JSON1
|
||||
DEFINES += 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
|
||||
|
||||
CONFIG(debug, debug|release): DEFINES += SQLITE_ENABLE_API_ARMOR
|
||||
|
||||
OTHER_FILES += README.md
|
||||
|
||||
|
@@ -3,7 +3,5 @@ win32:QMAKE_CXXFLAGS_DEBUG += -O2
|
||||
|
||||
include(../../qtcreatorlibrary.pri)
|
||||
|
||||
win32:DEFINES += SQLITE_API=__declspec(dllexport)
|
||||
unix:DEFINES += SQLITE_API=\"__attribute__((visibility(\\\"default\\\")))\"
|
||||
|
||||
include(sqlite-lib.pri)
|
||||
|
@@ -6,12 +6,16 @@ QtcLibrary {
|
||||
cpp.includePaths: base.concat(["../3rdparty/sqlite", "."])
|
||||
cpp.defines: base.concat([
|
||||
"BUILD_SQLITE_LIBRARY",
|
||||
"SQLITE_THREADSAFE=2",
|
||||
"SQLITE_ENABLE_FTS4",
|
||||
"SQLITE_ENABLE_FTS3_PARENTHESIS",
|
||||
"SQLITE_ENABLE_UNLOCK_NOTIFY",
|
||||
"SQLITE_ENABLE_COLUMN_METADATA",
|
||||
"SQLITE_ENABLE_JSON1"
|
||||
"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"
|
||||
])
|
||||
cpp.optimization: "fast"
|
||||
cpp.dynamicLibraries: base.concat((qbs.targetOS.contains("unix") && !qbs.targetOS.contains("bsd"))
|
||||
@@ -26,6 +30,7 @@ QtcLibrary {
|
||||
"sqlite3.c",
|
||||
"sqlite3.h",
|
||||
"sqlite3ext.h",
|
||||
"carray.c"
|
||||
]
|
||||
}
|
||||
|
||||
|
@@ -41,11 +41,10 @@
|
||||
namespace Sqlite {
|
||||
|
||||
BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database)
|
||||
: m_compiledStatement(nullptr, deleteCompiledStatement),
|
||||
m_database(database),
|
||||
m_bindingParameterCount(0),
|
||||
m_columnCount(0),
|
||||
m_isReadyToFetchValues(false)
|
||||
: m_compiledStatement(nullptr, deleteCompiledStatement)
|
||||
, m_database(database)
|
||||
, m_bindingParameterCount(0)
|
||||
, m_columnCount(0)
|
||||
{
|
||||
prepare(sqlStatement);
|
||||
setBindingParameterCount();
|
||||
@@ -107,11 +106,8 @@ void BaseStatement::reset() const
|
||||
{
|
||||
int resultCode = sqlite3_reset(m_compiledStatement.get());
|
||||
|
||||
if (resultCode != SQLITE_OK) {
|
||||
if (resultCode != SQLITE_OK)
|
||||
checkForResetError(resultCode);
|
||||
|
||||
m_isReadyToFetchValues = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseStatement::next() const
|
||||
@@ -127,8 +123,6 @@ bool BaseStatement::next() const
|
||||
|
||||
} while (resultCode == SQLITE_LOCKED);
|
||||
|
||||
setIfIsReadyToFetchValues(resultCode);
|
||||
|
||||
if (resultCode == SQLITE_ROW)
|
||||
return true;
|
||||
else if (resultCode == SQLITE_DONE)
|
||||
@@ -147,15 +141,11 @@ int BaseStatement::columnCount() const
|
||||
return m_columnCount;
|
||||
}
|
||||
|
||||
Utils::SmallStringVector BaseStatement::columnNames() const
|
||||
void BaseStatement::bind(int index, NullValue)
|
||||
{
|
||||
Utils::SmallStringVector columnNames;
|
||||
int columnCount = BaseStatement::columnCount();
|
||||
columnNames.reserve(std::size_t(columnCount));
|
||||
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
|
||||
columnNames.emplace_back(sqlite3_column_origin_name(m_compiledStatement.get(), columnIndex));
|
||||
|
||||
return columnNames;
|
||||
int resultCode = sqlite3_bind_null(m_compiledStatement.get(), index);
|
||||
if (resultCode != SQLITE_OK)
|
||||
checkForBindingError(resultCode);
|
||||
}
|
||||
|
||||
void BaseStatement::bind(int index, int value)
|
||||
@@ -179,6 +169,17 @@ void BaseStatement::bind(int index, double value)
|
||||
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)
|
||||
{
|
||||
int resultCode = sqlite3_bind_text(m_compiledStatement.get(),
|
||||
@@ -190,6 +191,17 @@ void BaseStatement::bind(int index, Utils::SmallStringView text)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int resultCode;
|
||||
@@ -252,11 +245,6 @@ sqlite3 *BaseStatement::sqliteDatabaseHandle() const
|
||||
return m_database.backend().sqliteDatabaseHandle();
|
||||
}
|
||||
|
||||
TextEncoding BaseStatement::databaseTextEncoding()
|
||||
{
|
||||
return m_database.backend().textEncoding();
|
||||
}
|
||||
|
||||
void BaseStatement::checkForStepError(int resultCode) const
|
||||
{
|
||||
switch (resultCode) {
|
||||
@@ -305,33 +293,10 @@ void BaseStatement::checkForBindingError(int resultCode) const
|
||||
throwUnknowError("SqliteStatement::bind: unknown error has happened");
|
||||
}
|
||||
|
||||
void BaseStatement::setIfIsReadyToFetchValues(int resultCode) const
|
||||
void BaseStatement::checkColumnCount(int columnCount) const
|
||||
{
|
||||
if (resultCode == SQLITE_ROW)
|
||||
m_isReadyToFetchValues = true;
|
||||
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!");
|
||||
if (columnCount != m_columnCount)
|
||||
throw ColumnCountDoesNotMatch("SqliteStatement::values: column count does not match!");
|
||||
}
|
||||
|
||||
void BaseStatement::checkBindingName(int index) const
|
||||
@@ -393,11 +358,6 @@ void BaseStatement::throwNoValuesToFetch(const char *whatHasHappened) const
|
||||
throw NoValuesToFetch(whatHasHappened);
|
||||
}
|
||||
|
||||
void BaseStatement::throwInvalidColumnFetched(const char *whatHasHappened) const
|
||||
{
|
||||
throw InvalidColumnFetched(whatHasHappened);
|
||||
}
|
||||
|
||||
void BaseStatement::throwBindingIndexIsOutOfRange(const char *whatHasHappened) const
|
||||
{
|
||||
throw BindingIndexIsOutOfRange(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
|
||||
@@ -431,8 +391,9 @@ Database &BaseStatement::database() const
|
||||
return m_database;
|
||||
}
|
||||
|
||||
namespace {
|
||||
template<typename StringType>
|
||||
static StringType textForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||
StringType textForColumn(sqlite3_stmt *sqlStatment, int 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));
|
||||
@@ -440,25 +401,43 @@ static StringType textForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||
return StringType(text, size);
|
||||
}
|
||||
|
||||
Utils::span<const byte> blobForColumn(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>
|
||||
static StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||
StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column)
|
||||
{
|
||||
int dataType = sqlite3_column_type(sqlStatment, column);
|
||||
switch (dataType) {
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
case SQLITE3_TEXT: return textForColumn<StringType>(sqlStatment, column);
|
||||
case SQLITE3_TEXT:
|
||||
return textForColumn<StringType>(sqlStatment, column);
|
||||
case SQLITE_BLOB:
|
||||
case SQLITE_NULL: break;
|
||||
case SQLITE_NULL:
|
||||
break;
|
||||
}
|
||||
|
||||
return StringType{"", 0};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int BaseStatement::fetchIntValue(int column) const
|
||||
{
|
||||
checkIfIsReadyToFetchValues();
|
||||
checkColumnIsValid(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
|
||||
{
|
||||
checkIfIsReadyToFetchValues();
|
||||
checkColumnIsValid(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
|
||||
{
|
||||
checkIfIsReadyToFetchValues();
|
||||
checkColumnIsValid(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<>
|
||||
double BaseStatement::fetchValue<double>(int column) const
|
||||
{
|
||||
@@ -508,8 +488,6 @@ double BaseStatement::fetchValue<double>(int column) const
|
||||
template<typename StringType>
|
||||
StringType BaseStatement::fetchValue(int column) const
|
||||
{
|
||||
checkIfIsReadyToFetchValues();
|
||||
checkColumnIsValid(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);
|
||||
switch (dataType) {
|
||||
case SQLITE_NULL:
|
||||
return ValueView::create(NullValue{});
|
||||
case SQLITE_INTEGER:
|
||||
return ValueView::create(fetchLongLongValue(column));
|
||||
case SQLITE_FLOAT:
|
||||
@@ -536,11 +516,10 @@ ValueView BaseStatement::fetchValueView(int column) const
|
||||
case SQLITE3_TEXT:
|
||||
return ValueView::create(fetchValue<Utils::SmallStringView>(column));
|
||||
case SQLITE_BLOB:
|
||||
case SQLITE_NULL:
|
||||
break;
|
||||
}
|
||||
|
||||
return ValueView::create(0LL);
|
||||
return ValueView::create(NullValue{});
|
||||
}
|
||||
|
||||
} // namespace Sqlite
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include <utils/smallstringvector.h>
|
||||
|
||||
#include <utils/optional.h>
|
||||
#include <utils/span.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
@@ -69,16 +70,19 @@ public:
|
||||
double fetchDoubleValue(int column) const;
|
||||
Utils::SmallStringView fetchSmallStringViewValue(int column) const;
|
||||
ValueView fetchValueView(int column) const;
|
||||
Utils::span<const byte> fetchBlobValue(int column) const;
|
||||
template<typename Type>
|
||||
Type fetchValue(int column) const;
|
||||
int columnCount() const;
|
||||
Utils::SmallStringVector columnNames() const;
|
||||
|
||||
void bind(int index, NullValue);
|
||||
void bind(int index, int fetchValue);
|
||||
void bind(int index, long long fetchValue);
|
||||
void bind(int index, double fetchValue);
|
||||
void bind(int index, void *pointer);
|
||||
void bind(int index, Utils::SmallStringView 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)); }
|
||||
|
||||
@@ -87,25 +91,17 @@ public:
|
||||
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 waitForUnlockNotify() const;
|
||||
|
||||
sqlite3 *sqliteDatabaseHandle() const;
|
||||
TextEncoding databaseTextEncoding();
|
||||
|
||||
[[noreturn]] void checkForStepError(int resultCode) const;
|
||||
[[noreturn]] void checkForResetError(int resultCode) const;
|
||||
[[noreturn]] void checkForPrepareError(int resultCode) const;
|
||||
[[noreturn]] void checkForBindingError(int resultCode) const;
|
||||
void setIfIsReadyToFetchValues(int resultCode) const;
|
||||
void checkIfIsReadyToFetchValues() const;
|
||||
void checkColumnsAreValid(const std::vector<int> &columns) const;
|
||||
void checkColumnIsValid(int column) const;
|
||||
void checkColumnCount(int columnCount) const;
|
||||
void checkBindingName(int index) const;
|
||||
void setBindingParameterCount();
|
||||
void setColumnCount();
|
||||
@@ -134,15 +130,8 @@ private:
|
||||
Database &m_database;
|
||||
int m_bindingParameterCount;
|
||||
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 long BaseStatement::fetchValue<long>(int column) const;
|
||||
template <> SQLITE_EXPORT long long BaseStatement::fetchValue<long long>(int column) const;
|
||||
@@ -184,32 +173,21 @@ public:
|
||||
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,
|
||||
int ResultTypeCount = 1>
|
||||
std::vector<ResultType> values(std::size_t reserveSize)
|
||||
{
|
||||
BaseStatement::checkColumnCount(ResultTypeCount);
|
||||
|
||||
Resetter resetter{*this};
|
||||
std::vector<ResultType> resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
|
||||
|
||||
while (BaseStatement::next())
|
||||
emplaceBackValues<ResultTypeCount>(resultValues);
|
||||
|
||||
setMaximumResultCount(resultValues.size());
|
||||
|
||||
resetter.reset();
|
||||
|
||||
return resultValues;
|
||||
@@ -220,15 +198,19 @@ public:
|
||||
typename... QueryTypes>
|
||||
std::vector<ResultType> values(std::size_t reserveSize, const QueryTypes&... queryValues)
|
||||
{
|
||||
BaseStatement::checkColumnCount(ResultTypeCount);
|
||||
|
||||
Resetter resetter{*this};
|
||||
std::vector<ResultType> resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
|
||||
|
||||
bindValues(queryValues...);
|
||||
|
||||
while (BaseStatement::next())
|
||||
emplaceBackValues<ResultTypeCount>(resultValues);
|
||||
|
||||
setMaximumResultCount(resultValues.size());
|
||||
|
||||
resetter.reset();
|
||||
|
||||
return resultValues;
|
||||
@@ -240,8 +222,10 @@ public:
|
||||
std::vector<ResultType> values(std::size_t reserveSize,
|
||||
const std::vector<QueryElementType> &queryValues)
|
||||
{
|
||||
BaseStatement::checkColumnCount(ResultTypeCount);
|
||||
|
||||
std::vector<ResultType> resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
|
||||
|
||||
for (const QueryElementType &queryValue : queryValues) {
|
||||
Resetter resetter{*this};
|
||||
@@ -250,6 +234,8 @@ public:
|
||||
while (BaseStatement::next())
|
||||
emplaceBackValues<ResultTypeCount>(resultValues);
|
||||
|
||||
setMaximumResultCount(resultValues.size());
|
||||
|
||||
resetter.reset();
|
||||
}
|
||||
|
||||
@@ -262,9 +248,11 @@ public:
|
||||
std::vector<ResultType> values(std::size_t reserveSize,
|
||||
const std::vector<std::tuple<QueryElementTypes...>> &queryTuples)
|
||||
{
|
||||
BaseStatement::checkColumnCount(ResultTypeCount);
|
||||
|
||||
using Container = std::vector<ResultType>;
|
||||
Container resultValues;
|
||||
resultValues.reserve(reserveSize);
|
||||
resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
|
||||
|
||||
for (const auto &queryTuple : queryTuples) {
|
||||
Resetter resetter{*this};
|
||||
@@ -273,6 +261,8 @@ public:
|
||||
while (BaseStatement::next())
|
||||
emplaceBackValues<ResultTypeCount>(resultValues);
|
||||
|
||||
setMaximumResultCount(resultValues.size());
|
||||
|
||||
resetter.reset();
|
||||
}
|
||||
|
||||
@@ -284,6 +274,8 @@ public:
|
||||
typename... QueryTypes>
|
||||
Utils::optional<ResultType> value(const QueryTypes&... queryValues)
|
||||
{
|
||||
BaseStatement::checkColumnCount(ResultTypeCount);
|
||||
|
||||
Resetter resetter{*this};
|
||||
Utils::optional<ResultType> resultValue;
|
||||
|
||||
@@ -302,6 +294,8 @@ public:
|
||||
{
|
||||
StatementImplementation statement(sqlStatement, database);
|
||||
|
||||
statement.checkColumnCount(1);
|
||||
|
||||
statement.next();
|
||||
|
||||
return statement.template fetchValue<Type>(0);
|
||||
@@ -354,6 +348,7 @@ private:
|
||||
operator long long() { return statement.fetchLongLongValue(column); }
|
||||
operator double() { return statement.fetchDoubleValue(column); }
|
||||
operator Utils::SmallStringView() { return statement.fetchSmallStringViewValue(column); }
|
||||
operator Utils::span<const Sqlite::byte>() { return statement.fetchBlobValue(column); }
|
||||
operator ValueView() { return statement.fetchValueView(column); }
|
||||
|
||||
StatementImplementation &statement;
|
||||
@@ -401,19 +396,6 @@ private:
|
||||
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>
|
||||
void bindTupleValuesElement(const TupleType &tuple, std::index_sequence<ColumnIndices...>)
|
||||
{
|
||||
@@ -427,6 +409,13 @@ private:
|
||||
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
|
||||
|
@@ -25,72 +25,50 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sqliteglobal.h"
|
||||
|
||||
#include <utils/smallstring.h>
|
||||
#include "constraints.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
|
||||
class Column
|
||||
{
|
||||
public:
|
||||
Column() = default;
|
||||
|
||||
Column(Utils::SmallString &&name,
|
||||
ColumnType type = ColumnType::Numeric,
|
||||
Contraint constraint = Contraint::NoConstraint)
|
||||
: m_name(std::move(name)),
|
||||
m_type(type),
|
||||
m_constraint(constraint)
|
||||
Column(Utils::SmallStringView tableName,
|
||||
Utils::SmallStringView name,
|
||||
ColumnType type,
|
||||
Constraints &&constraints = {})
|
||||
: constraints(std::move(constraints))
|
||||
, name(name)
|
||||
, tableName(tableName)
|
||||
, type(type)
|
||||
{}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_name.clear();
|
||||
m_type = ColumnType::Numeric;
|
||||
m_constraint = Contraint::NoConstraint;
|
||||
}
|
||||
|
||||
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;
|
||||
name.clear();
|
||||
type = ColumnType::Numeric;
|
||||
constraints = {};
|
||||
}
|
||||
|
||||
Utils::SmallString typeString() const
|
||||
{
|
||||
switch (m_type) {
|
||||
case ColumnType::None: return {};
|
||||
case ColumnType::Numeric: return "NUMERIC";
|
||||
case ColumnType::Integer: return "INTEGER";
|
||||
case ColumnType::Real: return "REAL";
|
||||
case ColumnType::Text: return "TEXT";
|
||||
switch (type) {
|
||||
case ColumnType::None:
|
||||
return {};
|
||||
case ColumnType::Numeric:
|
||||
return "NUMERIC";
|
||||
case ColumnType::Integer:
|
||||
return "INTEGER";
|
||||
case ColumnType::Real:
|
||||
return "REAL";
|
||||
case ColumnType::Text:
|
||||
return "TEXT";
|
||||
case ColumnType::Blob:
|
||||
return "BLOB";
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
@@ -98,16 +76,16 @@ public:
|
||||
|
||||
friend bool operator==(const Column &first, const Column &second)
|
||||
{
|
||||
return first.m_name == second.m_name
|
||||
&& first.m_type == second.m_type
|
||||
&& first.m_constraint == second.m_constraint;
|
||||
return first.name == second.name && first.type == second.type
|
||||
&& first.constraints == second.constraints && first.tableName == second.tableName;
|
||||
}
|
||||
|
||||
private:
|
||||
Utils::SmallString m_name;
|
||||
ColumnType m_type = ColumnType::Numeric;
|
||||
Contraint m_constraint = Contraint::NoConstraint;
|
||||
};
|
||||
public:
|
||||
Constraints constraints;
|
||||
Utils::SmallString name;
|
||||
Utils::SmallString tableName;
|
||||
ColumnType type = ColumnType::Numeric;
|
||||
}; // namespace Sqlite
|
||||
|
||||
using SqliteColumns = std::vector<Column>;
|
||||
using SqliteColumnConstReference = std::reference_wrapper<const Column>;
|
||||
|
@@ -25,9 +25,10 @@
|
||||
|
||||
#include "sqlitedatabase.h"
|
||||
|
||||
#include "sqlitereadwritestatement.h"
|
||||
#include "sqlitesessions.h"
|
||||
#include "sqlitetable.h"
|
||||
#include "sqlitetransaction.h"
|
||||
#include "sqlitereadwritestatement.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
@@ -51,6 +52,7 @@ public:
|
||||
ReadWriteStatement exclusiveBegin{"BEGIN EXCLUSIVE", database};
|
||||
ReadWriteStatement commitBegin{"COMMIT", database};
|
||||
ReadWriteStatement rollbackBegin{"ROLLBACK", database};
|
||||
Sessions sessions{database, "main", "databaseSessions"};
|
||||
};
|
||||
|
||||
Database::Database()
|
||||
@@ -60,21 +62,29 @@ Database::Database()
|
||||
|
||||
Database::Database(Utils::PathString &&databaseFilePath, JournalMode journalMode)
|
||||
: Database(std::move(databaseFilePath), 1000ms, journalMode)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
Database::Database(Utils::PathString &&databaseFilePath,
|
||||
std::chrono::milliseconds busyTimeout,
|
||||
JournalMode journalMode)
|
||||
: m_databaseBackend(*this),
|
||||
m_busyTimeout(busyTimeout)
|
||||
: m_databaseBackend(*this)
|
||||
, m_busyTimeout(busyTimeout)
|
||||
{
|
||||
setJournalMode(journalMode);
|
||||
open(std::move(databaseFilePath));
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
execute("PRAGMA reverse_unordered_selects=1");
|
||||
#endif
|
||||
}
|
||||
|
||||
Database::~Database() = default;
|
||||
|
||||
void Database::activateLogging()
|
||||
{
|
||||
DatabaseBackend::activateLogging();
|
||||
}
|
||||
|
||||
void Database::open()
|
||||
{
|
||||
m_databaseBackend.open(m_databaseFilePath, m_openMode);
|
||||
@@ -131,6 +141,16 @@ void Database::setDatabaseFilePath(Utils::PathString &&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
|
||||
{
|
||||
return m_databaseFilePath;
|
||||
@@ -210,6 +230,22 @@ void Database::rollback()
|
||||
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()
|
||||
{
|
||||
m_databaseMutex.lock();
|
||||
|
@@ -66,6 +66,8 @@ public:
|
||||
Database(const Database &) = delete;
|
||||
Database &operator=(const Database &) = delete;
|
||||
|
||||
static void activateLogging();
|
||||
|
||||
void open();
|
||||
void open(Utils::PathString &&databaseFilePath);
|
||||
void close();
|
||||
@@ -108,7 +110,21 @@ public:
|
||||
|
||||
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:
|
||||
void deferredBegin() override;
|
||||
@@ -118,6 +134,9 @@ private:
|
||||
void rollback() override;
|
||||
void lock() override;
|
||||
void unlock() override;
|
||||
void immediateSessionBegin() override;
|
||||
void sessionCommit() override;
|
||||
void sessionRollback() override;
|
||||
|
||||
void initializeTables();
|
||||
void registerTransactionStatements();
|
||||
|
@@ -37,12 +37,15 @@
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
extern "C" {
|
||||
int sqlite3_carray_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
|
||||
}
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
DatabaseBackend::DatabaseBackend(Database &database)
|
||||
: m_database(database),
|
||||
m_databaseHandle(nullptr),
|
||||
m_cachedTextEncoding(Utf8)
|
||||
: m_database(database)
|
||||
, m_databaseHandle(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -65,14 +68,16 @@ void DatabaseBackend::activateMultiThreading()
|
||||
|
||||
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()
|
||||
{
|
||||
if (qEnvironmentVariableIsSet("QTC_SQLITE_LOGGING")) {
|
||||
int resultCode = sqlite3_config(SQLITE_CONFIG_LOG, sqliteLog, nullptr);
|
||||
checkIfLoogingIsActivated(resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseBackend::initializeSqliteLibrary()
|
||||
{
|
||||
@@ -103,7 +108,9 @@ void DatabaseBackend::open(Utils::SmallStringView databaseFilePath, OpenMode mod
|
||||
|
||||
checkDatabaseCouldBeOpened(resultCode);
|
||||
|
||||
cacheTextEncoding();
|
||||
resultCode = sqlite3_carray_init(m_databaseHandle, nullptr, nullptr);
|
||||
|
||||
checkCarrayCannotBeIntialized(resultCode);
|
||||
}
|
||||
|
||||
sqlite3 *DatabaseBackend::sqliteDatabaseHandle() const
|
||||
@@ -135,24 +142,6 @@ JournalMode DatabaseBackend::journalMode()
|
||||
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
|
||||
{
|
||||
return sqlite3_changes(sqliteDatabaseHandle());
|
||||
@@ -232,11 +221,6 @@ int DatabaseBackend::busyHandlerCallback(void *, int counter)
|
||||
return true;
|
||||
}
|
||||
|
||||
void DatabaseBackend::cacheTextEncoding()
|
||||
{
|
||||
m_cachedTextEncoding = pragmaToTextEncoding(pragmaValue("encoding"));
|
||||
}
|
||||
|
||||
void DatabaseBackend::checkForOpenDatabaseWhichCanBeClosed()
|
||||
{
|
||||
if (m_databaseHandle == nullptr)
|
||||
@@ -272,10 +256,19 @@ void DatabaseBackend::checkDatabaseCouldBeOpened(int resultCode)
|
||||
return;
|
||||
default:
|
||||
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,
|
||||
Utils::SmallStringView expectedValue)
|
||||
{
|
||||
@@ -292,31 +285,35 @@ void DatabaseBackend::checkDatabaseHandleIsNotNull() const
|
||||
void DatabaseBackend::checkIfMultithreadingIsActivated(int resultCode)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (resultCode != SQLITE_OK)
|
||||
throwException("SqliteDatabaseBackend::initializeSqliteLibrary: SqliteLibrary cannot initialized!");
|
||||
throwExceptionStatic(
|
||||
"SqliteDatabaseBackend::initializeSqliteLibrary: SqliteLibrary cannot initialized!");
|
||||
}
|
||||
|
||||
void DatabaseBackend::checkShutdownSqliteLibraryWasSuccesful(int resultCode)
|
||||
{
|
||||
if (resultCode != SQLITE_OK)
|
||||
throwException("SqliteDatabaseBackend::shutdownSqliteLibrary: SqliteLibrary cannot be shutdowned!");
|
||||
throwExceptionStatic(
|
||||
"SqliteDatabaseBackend::shutdownSqliteLibrary: SqliteLibrary cannot be shutdowned!");
|
||||
}
|
||||
|
||||
void DatabaseBackend::checkIfLogCouldBeCheckpointed(int resultCode)
|
||||
@@ -344,13 +341,11 @@ int indexOfPragma(Utils::SmallStringView pragma, const Utils::SmallStringView (&
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const Utils::SmallStringView journalModeStrings[] = {
|
||||
"delete",
|
||||
const Utils::SmallStringView journalModeStrings[] = {"delete",
|
||||
"truncate",
|
||||
"persist",
|
||||
"memory",
|
||||
"wal"
|
||||
};
|
||||
"wal"};
|
||||
|
||||
Utils::SmallStringView DatabaseBackend::journalModeToPragma(JournalMode journalMode)
|
||||
{
|
||||
@@ -367,27 +362,6 @@ JournalMode DatabaseBackend::pragmaToJournalMode(Utils::SmallStringView pragma)
|
||||
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 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)
|
||||
{
|
||||
throw Exception(whatHasHappens);
|
||||
|
@@ -40,6 +40,9 @@ class Database;
|
||||
class SQLITE_EXPORT DatabaseBackend
|
||||
{
|
||||
public:
|
||||
using UpdateCallback
|
||||
= std::function<void(ChangeType type, char const *, char const *, long long)>;
|
||||
|
||||
DatabaseBackend(Database &database);
|
||||
~DatabaseBackend();
|
||||
|
||||
@@ -49,11 +52,11 @@ public:
|
||||
DatabaseBackend(DatabaseBackend &&) = delete;
|
||||
DatabaseBackend &operator=(DatabaseBackend &&) = delete;
|
||||
|
||||
void setMmapSize(qint64 defaultSize, qint64 maximumSize);
|
||||
void activateMultiThreading();
|
||||
void activateLogging();
|
||||
void initializeSqliteLibrary();
|
||||
void shutdownSqliteLibrary();
|
||||
static void setMmapSize(qint64 defaultSize, qint64 maximumSize);
|
||||
static void activateMultiThreading();
|
||||
static void activateLogging();
|
||||
static void initializeSqliteLibrary();
|
||||
static void shutdownSqliteLibrary();
|
||||
void checkpointFullWalLog();
|
||||
|
||||
void open(Utils::SmallStringView databaseFilePath, OpenMode openMode);
|
||||
@@ -65,9 +68,6 @@ public:
|
||||
void setJournalMode(JournalMode journalMode);
|
||||
JournalMode journalMode();
|
||||
|
||||
void setTextEncoding(TextEncoding textEncoding);
|
||||
TextEncoding textEncoding();
|
||||
|
||||
Utils::SmallStringVector columnNames(Utils::SmallStringView tableName);
|
||||
|
||||
int changesCount() const;
|
||||
@@ -87,6 +87,9 @@ public:
|
||||
|
||||
void walCheckpointFull();
|
||||
|
||||
void setUpdateHook(UpdateCallback &callback);
|
||||
void resetUpdateHook();
|
||||
|
||||
protected:
|
||||
bool databaseIsOpen() const;
|
||||
|
||||
@@ -97,27 +100,23 @@ protected:
|
||||
void registerRankingFunction();
|
||||
static int busyHandlerCallback(void*, int counter);
|
||||
|
||||
void cacheTextEncoding();
|
||||
|
||||
void checkForOpenDatabaseWhichCanBeClosed();
|
||||
void checkDatabaseClosing(int resultCode);
|
||||
void checkCanOpenDatabase(Utils::SmallStringView databaseFilePath);
|
||||
void checkDatabaseCouldBeOpened(int resultCode);
|
||||
void checkCarrayCannotBeIntialized(int resultCode);
|
||||
void checkPragmaValue(Utils::SmallStringView databaseValue, Utils::SmallStringView expectedValue);
|
||||
void checkDatabaseHandleIsNotNull() const;
|
||||
void checkIfMultithreadingIsActivated(int resultCode);
|
||||
void checkIfLoogingIsActivated(int resultCode);
|
||||
void checkMmapSizeIsSet(int resultCode);
|
||||
void checkInitializeSqliteLibraryWasSuccesful(int resultCode);
|
||||
void checkShutdownSqliteLibraryWasSuccesful(int resultCode);
|
||||
static void checkIfMultithreadingIsActivated(int resultCode);
|
||||
static void checkIfLoogingIsActivated(int resultCode);
|
||||
static void checkMmapSizeIsSet(int resultCode);
|
||||
static void checkInitializeSqliteLibraryWasSuccesful(int resultCode);
|
||||
static void checkShutdownSqliteLibraryWasSuccesful(int resultCode);
|
||||
void checkIfLogCouldBeCheckpointed(int resultCode);
|
||||
void checkIfBusyTimeoutWasSet(int resultCode);
|
||||
|
||||
static Utils::SmallStringView journalModeToPragma(JournalMode journalMode);
|
||||
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);
|
||||
[[noreturn]] void throwException(const char *whatHasHappens) const;
|
||||
@@ -127,8 +126,6 @@ protected:
|
||||
private:
|
||||
Database &m_database;
|
||||
sqlite3 *m_databaseHandle;
|
||||
TextEncoding m_cachedTextEncoding;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Sqlite
|
||||
|
@@ -25,11 +25,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utils/smallstringvector.h>
|
||||
|
||||
#include "sqliteglobal.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace Sqlite {
|
||||
class DatabaseInterface
|
||||
{
|
||||
public:
|
||||
using UpdateCallback
|
||||
= std::function<void(ChangeType type, char const *, char const *, long long)>;
|
||||
|
||||
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:
|
||||
~DatabaseInterface() = default;
|
||||
|
@@ -29,17 +29,21 @@
|
||||
|
||||
#include <utils/smallstring.h>
|
||||
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
class SQLITE_EXPORT Exception
|
||||
class SQLITE_EXPORT Exception : public std::exception
|
||||
{
|
||||
public:
|
||||
Exception(const char *whatErrorHasHappen,
|
||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||
: m_whatErrorHasHappen(whatErrorHasHappen),
|
||||
m_sqliteErrorMessage(std::move(sqliteErrorMessage))
|
||||
{
|
||||
}
|
||||
: m_whatErrorHasHappen(whatErrorHasHappen)
|
||||
, m_sqliteErrorMessage(std::move(sqliteErrorMessage))
|
||||
{}
|
||||
|
||||
const char *what() const noexcept override { return m_whatErrorHasHappen; }
|
||||
|
||||
void printWarning() const;
|
||||
|
||||
@@ -115,13 +119,12 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class InvalidColumnFetched : public Exception
|
||||
class ColumnCountDoesNotMatch : public Exception
|
||||
{
|
||||
public:
|
||||
InvalidColumnFetched(const char *whatErrorHasHappen)
|
||||
ColumnCountDoesNotMatch(const char *whatErrorHasHappen)
|
||||
: Exception(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
{}
|
||||
};
|
||||
|
||||
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
|
||||
|
@@ -39,26 +39,15 @@
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
enum class ColumnType : char
|
||||
{
|
||||
Numeric,
|
||||
Integer,
|
||||
Real,
|
||||
Text,
|
||||
None
|
||||
};
|
||||
enum class ColumnType : char { Numeric, Integer, Real, Text, Blob, None };
|
||||
|
||||
enum class Contraint : char
|
||||
{
|
||||
NoConstraint,
|
||||
PrimaryKey,
|
||||
Unique
|
||||
};
|
||||
enum class ConstraintType : char { NoConstraint, PrimaryKey, Unique, ForeignKey };
|
||||
|
||||
enum class ColumnConstraint : char
|
||||
{
|
||||
PrimaryKey
|
||||
};
|
||||
enum class ForeignKeyAction : char { NoAction, Restrict, SetNull, SetDefault, Cascade };
|
||||
|
||||
enum class Enforment : char { Immediate, Deferred };
|
||||
|
||||
enum class ColumnConstraint : char { PrimaryKey };
|
||||
|
||||
enum class JournalMode : char
|
||||
{
|
||||
@@ -75,17 +64,8 @@ enum class OpenMode : char
|
||||
ReadWrite
|
||||
};
|
||||
|
||||
enum TextEncoding : char
|
||||
{
|
||||
Utf8,
|
||||
Utf16le,
|
||||
Utf16be,
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
Utf16 = Utf16le
|
||||
#else
|
||||
Utf16 = Utf16be
|
||||
#endif
|
||||
enum class ChangeType : int { Delete = 9, Insert = 18, Update = 23 };
|
||||
|
||||
};
|
||||
enum class byte : unsigned char {};
|
||||
|
||||
} // namespace Sqlite
|
||||
|
@@ -41,7 +41,6 @@ public:
|
||||
using StatementImplementation::values;
|
||||
using StatementImplementation::toValue;
|
||||
using StatementImplementation::write;
|
||||
using StatementImplementation::writeNamed;
|
||||
};
|
||||
|
||||
} // 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);
|
||||
}
|
||||
|
||||
void setName(Utils::SmallString &&name)
|
||||
{
|
||||
m_tableName = std::move(name);
|
||||
}
|
||||
void setName(Utils::SmallStringView name) { m_tableName = name; }
|
||||
|
||||
Utils::SmallStringView name() const
|
||||
{
|
||||
@@ -74,15 +71,69 @@ public:
|
||||
m_useTemporaryTable = useTemporaryTable;
|
||||
}
|
||||
|
||||
Column &addColumn(Utils::SmallString &&name,
|
||||
Column &addColumn(Utils::SmallStringView name,
|
||||
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();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
m_sqliteIndices.emplace_back(m_tableName.clone(), sqliteColumnNames(columns));
|
||||
@@ -119,6 +170,7 @@ public:
|
||||
builder.setUseIfNotExists(m_useIfNotExists);
|
||||
builder.setUseTemporaryTable(m_useTemporaryTable);
|
||||
builder.setColumns(m_sqliteColumns);
|
||||
builder.setConstraints(m_tableConstraints);
|
||||
|
||||
database.execute(builder.sqlStatement());
|
||||
|
||||
@@ -142,13 +194,23 @@ public:
|
||||
&& 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:
|
||||
Utils::SmallStringVector sqliteColumnNames(const SqliteColumnConstReferences &columns)
|
||||
{
|
||||
Utils::SmallStringVector columnNames;
|
||||
|
||||
for (const Column &column : columns)
|
||||
columnNames.push_back(column.name());
|
||||
columnNames.push_back(column.name);
|
||||
|
||||
return columnNames;
|
||||
}
|
||||
@@ -157,6 +219,7 @@ private:
|
||||
Utils::SmallString m_tableName;
|
||||
SqliteColumns m_sqliteColumns;
|
||||
SqliteIndices m_sqliteIndices;
|
||||
TableConstraints m_tableConstraints;
|
||||
bool m_withoutRowId = false;
|
||||
bool m_useIfNotExists = false;
|
||||
bool m_useTemporaryTable = false;
|
||||
|
@@ -27,6 +27,8 @@
|
||||
|
||||
#include "sqliteglobal.h"
|
||||
|
||||
#include <utils/smallstringview.h>
|
||||
|
||||
#include <exception>
|
||||
#include <mutex>
|
||||
|
||||
@@ -49,6 +51,9 @@ public:
|
||||
virtual void rollback() = 0;
|
||||
virtual void lock() = 0;
|
||||
virtual void unlock() = 0;
|
||||
virtual void immediateSessionBegin() = 0;
|
||||
virtual void sessionCommit() = 0;
|
||||
virtual void sessionRollback() = 0;
|
||||
|
||||
protected:
|
||||
~TransactionInterface() = default;
|
||||
@@ -82,6 +87,42 @@ protected:
|
||||
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
|
||||
{
|
||||
public:
|
||||
@@ -181,6 +222,23 @@ public:
|
||||
};
|
||||
|
||||
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
|
||||
|
@@ -30,17 +30,29 @@
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
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>
|
||||
class ValueBase
|
||||
{
|
||||
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)
|
||||
: 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); }
|
||||
|
||||
double toFloat() const { return Utils::get<int(ValueType::Float)>(value); }
|
||||
@@ -93,6 +107,8 @@ public:
|
||||
return {};
|
||||
}
|
||||
|
||||
friend bool operator==(const ValueBase &first, std::nullptr_t) { return first.isNull(); }
|
||||
|
||||
friend bool operator==(const ValueBase &first, long long second)
|
||||
{
|
||||
auto maybeInteger = Utils::get_if<int(ValueType::Integer)>(&first.value);
|
||||
@@ -171,10 +187,12 @@ public:
|
||||
{
|
||||
switch (value.index()) {
|
||||
case 0:
|
||||
return ValueType::Integer;
|
||||
return ValueType::Null;
|
||||
case 1:
|
||||
return ValueType::Float;
|
||||
return ValueType::Integer;
|
||||
case 2:
|
||||
return ValueType::Float;
|
||||
case 3:
|
||||
return ValueType::String;
|
||||
}
|
||||
|
||||
@@ -206,6 +224,10 @@ class Value : public ValueBase<Utils::SmallString>
|
||||
public:
|
||||
using Base::Base;
|
||||
|
||||
Value() = default;
|
||||
|
||||
explicit Value(NullValue) {}
|
||||
|
||||
explicit Value(ValueView view)
|
||||
: ValueBase(convert(view))
|
||||
{}
|
||||
@@ -226,6 +248,10 @@ public:
|
||||
: 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)
|
||||
{
|
||||
return !(first.value == second.value);
|
||||
@@ -265,6 +291,9 @@ public:
|
||||
private:
|
||||
static Base::VariantType convert(const QVariant &value)
|
||||
{
|
||||
if (value.isNull())
|
||||
return VariantType{NullValue{}};
|
||||
|
||||
switch (value.type()) {
|
||||
case QVariant::Int:
|
||||
return VariantType{static_cast<long long>(value.toInt())};
|
||||
@@ -284,6 +313,8 @@ private:
|
||||
static Base::VariantType convert(ValueView view)
|
||||
{
|
||||
switch (view.type()) {
|
||||
case ValueType::Null:
|
||||
return VariantType(NullValue{});
|
||||
case ValueType::Integer:
|
||||
return VariantType{view.toInteger()};
|
||||
case ValueType::Float:
|
||||
|
@@ -37,7 +37,6 @@ public:
|
||||
using StatementImplementation::execute;
|
||||
using StatementImplementation::database;
|
||||
using StatementImplementation::write;
|
||||
using StatementImplementation::writeNamed;
|
||||
|
||||
protected:
|
||||
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
|
||||
../3rdparty/optional/optional.hpp
|
||||
../3rdparty/variant/variant.hpp
|
||||
../3rdparty/span/span.hpp
|
||||
QtConcurrentTools
|
||||
algorithm.h
|
||||
ansiescapecodehandler.cpp ansiescapecodehandler.h
|
||||
@@ -137,6 +138,7 @@ add_qtc_library(Utils
|
||||
smallstringmemory.h
|
||||
smallstringvector.h
|
||||
smallstringview.h
|
||||
span.h
|
||||
statuslabel.cpp statuslabel.h
|
||||
stringutils.cpp stringutils.h
|
||||
styledbar.cpp styledbar.h
|
||||
|
@@ -90,39 +90,35 @@ public:
|
||||
constexpr
|
||||
BasicSmallString(const char(&string)[ArraySize])
|
||||
: m_data(string)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
BasicSmallString(const char *string, size_type size, size_type capacity)
|
||||
{
|
||||
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.control.setShortStringSize(size);
|
||||
m_data.shortString.control.setIsShortString(true);
|
||||
m_data.shortString.control.setIsReadOnlyReference(false);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
explicit BasicSmallString(SmallStringView stringView)
|
||||
: BasicSmallString(stringView.data(), stringView.size(), stringView.size())
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
BasicSmallString(const char *string, size_type size)
|
||||
: BasicSmallString(string, size, size)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Type,
|
||||
typename = std::enable_if_t<std::is_pointer<Type>::value>
|
||||
>
|
||||
template<typename Type, typename = std::enable_if_t<std::is_pointer<Type>::value>>
|
||||
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!");
|
||||
}
|
||||
@@ -211,8 +207,7 @@ public:
|
||||
return clonedString;
|
||||
}
|
||||
|
||||
friend
|
||||
void swap(BasicSmallString &first, BasicSmallString &second)
|
||||
friend void swap(BasicSmallString &first, BasicSmallString &second) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
@@ -254,7 +249,7 @@ public:
|
||||
static
|
||||
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)
|
||||
@@ -272,7 +267,7 @@ public:
|
||||
const char *oldData = data();
|
||||
|
||||
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;
|
||||
initializeLongString(oldSize, newCapacity);
|
||||
}
|
||||
@@ -381,7 +376,7 @@ public:
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -389,7 +384,9 @@ public:
|
||||
bool startsWith(SmallStringView subStringToSearch) const noexcept
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -402,7 +399,8 @@ public:
|
||||
bool endsWith(SmallStringView subStringToSearch) const noexcept
|
||||
{
|
||||
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.size());
|
||||
return comparison == 0;
|
||||
@@ -463,7 +461,7 @@ public:
|
||||
size_type newSize = oldSize + string.size();
|
||||
|
||||
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;
|
||||
setSize(newSize);
|
||||
}
|
||||
@@ -725,7 +723,7 @@ private:
|
||||
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.size = size;
|
||||
@@ -758,7 +756,7 @@ private:
|
||||
while (found != end()) {
|
||||
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,
|
||||
end(),
|
||||
|
@@ -25,6 +25,18 @@
|
||||
|
||||
#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;
|
||||
|
||||
namespace Utils {
|
||||
@@ -35,9 +47,4 @@ class BasicSmallString;
|
||||
using SmallString = BasicSmallString<31>;
|
||||
using PathString = BasicSmallString<190>;
|
||||
|
||||
inline
|
||||
int compare(SmallStringView first, SmallStringView second) noexcept;
|
||||
inline
|
||||
int reverseCompare(SmallStringView first, SmallStringView second) noexcept;
|
||||
|
||||
} // namespace Utils
|
||||
|
@@ -230,30 +230,6 @@ QDataStream &operator>>(QDataStream &in, vector<Type> &vector)
|
||||
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
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
@@ -37,118 +37,89 @@ template <class Category,
|
||||
typename DistanceType = ptrdiff_t,
|
||||
typename Pointer = Type *,
|
||||
typename Reference = Type &>
|
||||
struct SmallStringIterator : public std::iterator<Category, Type, DistanceType, Pointer, Reference>
|
||||
struct SmallStringIterator
|
||||
{
|
||||
constexpr
|
||||
SmallStringIterator() noexcept = default;
|
||||
using iterator_category = Category;
|
||||
using value_type = Type;
|
||||
using difference_type = DistanceType;
|
||||
using pointer = Pointer;
|
||||
using reference = Reference;
|
||||
|
||||
constexpr
|
||||
SmallStringIterator(Pointer ptr) noexcept : pointer_(ptr)
|
||||
{
|
||||
}
|
||||
constexpr SmallStringIterator() noexcept = default;
|
||||
|
||||
SmallStringIterator operator++() noexcept
|
||||
{
|
||||
return ++pointer_;
|
||||
}
|
||||
constexpr SmallStringIterator(Pointer ptr) noexcept
|
||||
: pointer_(ptr)
|
||||
{}
|
||||
|
||||
SmallStringIterator operator++(int) noexcept
|
||||
{
|
||||
return pointer_++;
|
||||
}
|
||||
constexpr SmallStringIterator operator++() noexcept { return ++pointer_; }
|
||||
|
||||
SmallStringIterator operator--() noexcept
|
||||
{
|
||||
return --pointer_;
|
||||
}
|
||||
constexpr SmallStringIterator operator++(int) noexcept { return pointer_++; }
|
||||
|
||||
SmallStringIterator operator--(int) noexcept
|
||||
{
|
||||
return pointer_--;
|
||||
}
|
||||
constexpr SmallStringIterator operator--() noexcept { 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;
|
||||
}
|
||||
|
||||
SmallStringIterator operator-(DistanceType difference) const noexcept
|
||||
constexpr SmallStringIterator operator-(DistanceType difference) const noexcept
|
||||
{
|
||||
return pointer_ - difference;
|
||||
}
|
||||
|
||||
SmallStringIterator operator+(std::size_t difference) const noexcept
|
||||
constexpr SmallStringIterator operator+(std::size_t difference) const noexcept
|
||||
{
|
||||
return pointer_ + difference;
|
||||
}
|
||||
|
||||
SmallStringIterator operator-(std::size_t difference) const noexcept
|
||||
constexpr SmallStringIterator operator-(std::size_t difference) const noexcept
|
||||
{
|
||||
return pointer_ - difference;
|
||||
}
|
||||
|
||||
DistanceType operator-(SmallStringIterator other) const noexcept
|
||||
constexpr DistanceType operator-(SmallStringIterator other) const noexcept
|
||||
{
|
||||
return pointer_ - other.data();
|
||||
}
|
||||
|
||||
SmallStringIterator operator+=(DistanceType difference) noexcept
|
||||
constexpr SmallStringIterator operator+=(DistanceType difference) noexcept
|
||||
{
|
||||
return pointer_ += difference;
|
||||
}
|
||||
|
||||
SmallStringIterator operator-=(DistanceType difference) noexcept
|
||||
constexpr SmallStringIterator operator-=(DistanceType difference) noexcept
|
||||
{
|
||||
return pointer_ -= difference;
|
||||
}
|
||||
|
||||
Reference operator*() noexcept
|
||||
{
|
||||
return *pointer_;
|
||||
}
|
||||
constexpr Reference operator*() noexcept { return *pointer_; }
|
||||
|
||||
const Reference operator*() const noexcept
|
||||
{
|
||||
return *pointer_;
|
||||
}
|
||||
const Reference operator*() const noexcept { return *pointer_; }
|
||||
|
||||
Pointer operator->() noexcept
|
||||
{
|
||||
return pointer_;
|
||||
}
|
||||
constexpr Pointer operator->() noexcept { return pointer_; }
|
||||
|
||||
const Pointer operator->() const noexcept
|
||||
{
|
||||
return pointer_;
|
||||
}
|
||||
constexpr const Pointer operator->() const noexcept { return pointer_; }
|
||||
|
||||
constexpr
|
||||
bool operator==(SmallStringIterator other) const noexcept
|
||||
constexpr bool operator==(SmallStringIterator other) const noexcept
|
||||
{
|
||||
return pointer_ == other.pointer_;
|
||||
}
|
||||
|
||||
constexpr
|
||||
bool operator!=(SmallStringIterator other) const noexcept
|
||||
constexpr bool operator!=(SmallStringIterator other) const noexcept
|
||||
{
|
||||
return pointer_ != other.pointer_;
|
||||
}
|
||||
|
||||
constexpr
|
||||
bool operator<(SmallStringIterator other) const noexcept
|
||||
constexpr bool operator<(SmallStringIterator other) const noexcept
|
||||
{
|
||||
return pointer_ < other.pointer_;
|
||||
}
|
||||
|
||||
Pointer data() noexcept
|
||||
{
|
||||
return pointer_;
|
||||
}
|
||||
constexpr Pointer data() noexcept { return pointer_; }
|
||||
|
||||
const Pointer data() const noexcept
|
||||
{
|
||||
return pointer_;
|
||||
}
|
||||
constexpr const Pointer data() const noexcept { return pointer_; }
|
||||
|
||||
private:
|
||||
Pointer pointer_ = nullptr;
|
||||
|
@@ -49,30 +49,21 @@ struct ControlBlock
|
||||
m_isReference(isReference)
|
||||
{}
|
||||
|
||||
void setShortStringSize(size_type size)
|
||||
constexpr void setShortStringSize(size_type size)
|
||||
{
|
||||
m_shortStringSize = static_cast<SizeType>(size);
|
||||
}
|
||||
|
||||
size_type shortStringSize() const
|
||||
{
|
||||
return m_shortStringSize;
|
||||
}
|
||||
constexpr size_type shortStringSize() const { return m_shortStringSize; }
|
||||
|
||||
void setIsReadOnlyReference(bool isReadOnlyReference)
|
||||
constexpr void setIsReadOnlyReference(bool isReadOnlyReference)
|
||||
{
|
||||
m_isReadOnlyReference = isReadOnlyReference;
|
||||
}
|
||||
|
||||
void setIsReference(bool isReference)
|
||||
{
|
||||
m_isReference = isReference;
|
||||
}
|
||||
constexpr void setIsReference(bool isReference) { m_isReference = isReference; }
|
||||
|
||||
void setIsShortString(bool isShortString)
|
||||
{
|
||||
m_isReference = !isShortString;
|
||||
}
|
||||
constexpr void setIsShortString(bool isShortString) { m_isReference = !isShortString; }
|
||||
|
||||
constexpr
|
||||
SizeType stringSize() const
|
||||
@@ -168,7 +159,7 @@ struct StringDataLayout {
|
||||
|
||||
template<size_type Size,
|
||||
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>{})
|
||||
{
|
||||
for (size_type i = 0; i < Size; ++i)
|
||||
|
@@ -37,34 +37,24 @@ namespace Memory {
|
||||
|
||||
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));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void deallocate(char *memory)
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
_aligned_free(memory);
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
|
||||
#endif
|
||||
std::free(memory);
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
inline char *reallocate(char *oldMemory, std::size_t newSize)
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
return static_cast<char*>(_aligned_realloc(oldMemory, newSize, 64));
|
||||
#else
|
||||
return static_cast<char *>(std::realloc(oldMemory, newSize));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Memory
|
||||
|
@@ -25,6 +25,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "smallstringfwd.h"
|
||||
#include "smallstringiterator.h"
|
||||
|
||||
#include <QString>
|
||||
@@ -53,49 +54,32 @@ public:
|
||||
|
||||
constexpr SmallStringView() = default;
|
||||
|
||||
template<size_type Size>
|
||||
constexpr
|
||||
SmallStringView(const char(&string)[Size]) noexcept
|
||||
: 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())
|
||||
constexpr17 SmallStringView(const char *characterPointer) noexcept
|
||||
: m_pointer(characterPointer)
|
||||
, m_size(std::char_traits<char>::length(characterPointer))
|
||||
{}
|
||||
|
||||
static
|
||||
SmallStringView fromUtf8(const char *const characterPointer)
|
||||
constexpr SmallStringView(const char *const string, const size_type size) noexcept
|
||||
: 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
|
||||
@@ -146,93 +130,85 @@ public:
|
||||
return data() + size();
|
||||
}
|
||||
|
||||
const_reverse_iterator rbegin() const noexcept
|
||||
constexpr17 const_reverse_iterator rbegin() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
const_reverse_iterator rend() const noexcept
|
||||
constexpr17 const_reverse_iterator rend() const noexcept
|
||||
{
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
operator std::string() const
|
||||
{
|
||||
return std::string(data(), size());
|
||||
}
|
||||
constexpr20 operator std::string() const { return std::string(data(), size()); }
|
||||
|
||||
explicit operator QString() const
|
||||
{
|
||||
return QString::fromUtf8(data(), int(size()));
|
||||
}
|
||||
|
||||
bool startsWith(SmallStringView subStringToSearch) const noexcept
|
||||
constexpr17 bool startsWith(SmallStringView subStringToSearch) const noexcept
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool startsWith(char characterToSearch) const noexcept
|
||||
constexpr bool startsWith(char characterToSearch) const noexcept
|
||||
{
|
||||
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:
|
||||
const char *m_pointer = "";
|
||||
size_type m_size = 0;
|
||||
};
|
||||
|
||||
inline
|
||||
bool operator==(SmallStringView first, SmallStringView second) noexcept
|
||||
constexpr17 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
|
||||
bool operator!=(SmallStringView first, SmallStringView second) noexcept
|
||||
constexpr17 bool operator!=(SmallStringView first, SmallStringView second) noexcept
|
||||
{
|
||||
return !(first == second);
|
||||
}
|
||||
|
||||
inline
|
||||
int compare(SmallStringView first, SmallStringView second) noexcept
|
||||
constexpr17 int compare(SmallStringView first, SmallStringView second) noexcept
|
||||
{
|
||||
int sizeDifference = int(first.size() - second.size());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
inline
|
||||
bool operator<(SmallStringView first, SmallStringView second) noexcept
|
||||
constexpr17 bool operator<(SmallStringView first, SmallStringView second) noexcept
|
||||
{
|
||||
return compare(first, second) < 0;
|
||||
}
|
||||
|
||||
inline
|
||||
bool operator>(SmallStringView first, SmallStringView second) noexcept
|
||||
constexpr17 bool operator>(SmallStringView first, SmallStringView second) noexcept
|
||||
{
|
||||
return second < first;
|
||||
}
|
||||
|
||||
namespace Internal {
|
||||
inline
|
||||
int reverse_memcmp(const char *first, const char *second, size_t n)
|
||||
constexpr int reverse_memcmp(const char *first, const char *second, size_t n)
|
||||
{
|
||||
|
||||
const char *currentFirst = first + n - 1;
|
||||
const char *currentSecond = second + n - 1;
|
||||
|
||||
while (n > 0)
|
||||
{
|
||||
while (n > 0) {
|
||||
// If the current characters differ, return an appropriately signed
|
||||
// value; otherwise, keep searching backwards
|
||||
int difference = *currentFirst - *currentSecond;
|
||||
@@ -246,10 +222,9 @@ int reverse_memcmp(const char *first, const char *second, size_t n)
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // namespace Internal
|
||||
|
||||
inline
|
||||
int reverseCompare(SmallStringView first, SmallStringView second) noexcept
|
||||
constexpr int reverseCompare(SmallStringView first, SmallStringView second) noexcept
|
||||
{
|
||||
int sizeDifference = int(first.size() - second.size());
|
||||
|
||||
@@ -261,10 +236,7 @@ int reverseCompare(SmallStringView first, SmallStringView second) noexcept
|
||||
|
||||
} // namespace Utils
|
||||
|
||||
#ifdef __cpp_user_defined_literals
|
||||
inline
|
||||
constexpr Utils::SmallStringView operator""_sv(const char *const string, size_t 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/qrcparser.h \
|
||||
$$PWD/qtcprocess.h \
|
||||
$$PWD/span.h \
|
||||
$$PWD/../3rdparty/span/span.hpp \
|
||||
$$PWD/utils_global.h \
|
||||
$$PWD/reloadpromptutils.h \
|
||||
$$PWD/settingsaccessor.h \
|
||||
|
@@ -245,6 +245,8 @@ Project {
|
||||
"smallstringlayout.h",
|
||||
"smallstringmemory.h",
|
||||
"smallstringvector.h",
|
||||
"span.h",
|
||||
"../3rdparty/span/span.hpp",
|
||||
"statuslabel.cpp",
|
||||
"statuslabel.h",
|
||||
"stringutils.cpp",
|
||||
|
@@ -37,6 +37,7 @@ using std::get;
|
||||
using std::get_if;
|
||||
using std::holds_alternative;
|
||||
using std::variant;
|
||||
using std::visit;
|
||||
} // namespace Utils
|
||||
|
||||
#else
|
||||
@@ -47,6 +48,7 @@ using mpark::get;
|
||||
using mpark::get_if;
|
||||
using mpark::holds_alternative;
|
||||
using mpark::variant;
|
||||
using mpark::visit;
|
||||
} // namespace Utils
|
||||
|
||||
#endif
|
||||
|
@@ -134,6 +134,8 @@ extend_qtc_plugin(QmlDesigner
|
||||
reparentinstancescommand.cpp reparentinstancescommand.h
|
||||
statepreviewimagechangedcommand.cpp statepreviewimagechangedcommand.h
|
||||
synchronizecommand.cpp synchronizecommand.h
|
||||
changepreviewimagesizecommand.cpp changepreviewimagesizecommand.h
|
||||
changelanguagecommand.cpp changelanguagecommand.h
|
||||
tokencommand.cpp tokencommand.h
|
||||
valueschangedcommand.cpp valueschangedcommand.h
|
||||
changeselectioncommand.cpp changeselectioncommand.h
|
||||
@@ -457,6 +459,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
include/rewriterview.h
|
||||
include/rewritingexception.h
|
||||
include/signalhandlerproperty.h
|
||||
include/stylesheetmerger.h
|
||||
include/subcomponentmanager.h
|
||||
include/textmodifier.h
|
||||
include/variantproperty.h
|
||||
@@ -530,6 +533,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
model/rewriteactioncompressor.cpp model/rewriteactioncompressor.h
|
||||
model/rewriterview.cpp
|
||||
model/signalhandlerproperty.cpp
|
||||
model/stylesheetmerger.cpp
|
||||
model/textmodifier.cpp
|
||||
model/texttomodelmerger.cpp model/texttomodelmerger.h
|
||||
model/variantproperty.cpp
|
||||
@@ -557,6 +561,7 @@ extend_qtc_plugin(QmlDesigner
|
||||
SOURCES_PREFIX components/annotationeditor
|
||||
SOURCES annotationcommenttab.cpp annotationcommenttab.h annotationcommenttab.ui
|
||||
annotationeditordialog.cpp annotationeditordialog.h annotationeditordialog.ui
|
||||
globalannotationeditordialog.cpp globalannotationeditordialog.h globalannotationeditordialog.ui
|
||||
annotationeditor.cpp annotationeditor.h
|
||||
annotationtool.cpp annotationtool.h
|
||||
globalannotationeditor.cpp globalannotationeditor.h
|
||||
|
@@ -79,7 +79,7 @@ void AnnotationCommentTab::resetUI()
|
||||
{
|
||||
ui->titleEdit->setText(m_comment.title());
|
||||
ui->authorEdit->setText(m_comment.author());
|
||||
m_editor->setRichText(m_comment.text());
|
||||
m_editor->setRichText(m_comment.deescapedText());
|
||||
|
||||
if (m_comment.timestamp() > 0)
|
||||
ui->timeLabel->setText(m_comment.timestampStr());
|
||||
|
@@ -3,12 +3,15 @@ HEADERS += $$PWD/annotationcommenttab.h
|
||||
HEADERS += $$PWD/annotationeditordialog.h
|
||||
HEADERS += $$PWD/annotationeditor.h
|
||||
HEADERS += $$PWD/globalannotationeditor.h
|
||||
HEADERS += $$PWD/globalannotationeditordialog.h
|
||||
|
||||
SOURCES += $$PWD/annotationtool.cpp
|
||||
SOURCES += $$PWD/annotationcommenttab.cpp
|
||||
SOURCES += $$PWD/annotationeditordialog.cpp
|
||||
SOURCES += $$PWD/annotationeditor.cpp
|
||||
SOURCES += $$PWD/globalannotationeditor.cpp
|
||||
SOURCES += $$PWD/globalannotationeditordialog.cpp
|
||||
|
||||
FORMS += $$PWD/annotationcommenttab.ui
|
||||
FORMS += $$PWD/annotationeditordialog.ui
|
||||
FORMS += $$PWD/globalannotationeditordialog.ui
|
||||
|
@@ -40,12 +40,11 @@
|
||||
|
||||
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)
|
||||
, ui(new Ui::AnnotationEditorDialog)
|
||||
, m_customId(customId)
|
||||
, m_annotation(annotation)
|
||||
, m_editorMode(mode)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
@@ -98,8 +97,8 @@ AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &t
|
||||
ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner);
|
||||
ui->targetIdEdit->setText(targetId);
|
||||
|
||||
changeEditorMode(m_editorMode);
|
||||
fillFields();
|
||||
setWindowTitle(annotationEditorTitle);
|
||||
}
|
||||
|
||||
AnnotationEditorDialog::~AnnotationEditorDialog()
|
||||
@@ -129,39 +128,6 @@ QString AnnotationEditorDialog::customId() const
|
||||
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()
|
||||
{
|
||||
m_customId = ui->customIdEdit->text();
|
||||
|
@@ -40,10 +40,7 @@ class AnnotationEditorDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum EditorMode { ItemAnnotation, GlobalAnnotation };
|
||||
|
||||
explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation,
|
||||
EditorMode mode = EditorMode::ItemAnnotation);
|
||||
explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation);
|
||||
~AnnotationEditorDialog();
|
||||
|
||||
void setAnnotation(const Annotation &annotation);
|
||||
@@ -52,9 +49,6 @@ public:
|
||||
void setCustomId(const QString &customId);
|
||||
QString customId() const;
|
||||
|
||||
void changeEditorMode(EditorMode mode);
|
||||
EditorMode editorMode() const;
|
||||
|
||||
signals:
|
||||
void accepted();
|
||||
|
||||
@@ -75,14 +69,11 @@ private:
|
||||
|
||||
private:
|
||||
const QString annotationEditorTitle = {tr("Annotation Editor")};
|
||||
const QString globalEditorTitle = {tr("Global Annotation Editor")};
|
||||
const QString defaultTabName = {tr("Annotation")};
|
||||
Ui::AnnotationEditorDialog *ui;
|
||||
|
||||
QString m_customId;
|
||||
Annotation m_annotation;
|
||||
|
||||
EditorMode m_editorMode;
|
||||
};
|
||||
|
||||
} //namespace QmlDesigner
|
||||
|
@@ -6,15 +6,16 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1100</width>
|
||||
<height>600</height>
|
||||
<width>1344</width>
|
||||
<height>819</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QWidget" name="annotationContainer" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="targetIdLayout">
|
||||
@@ -52,6 +53,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
|
@@ -25,7 +25,7 @@
|
||||
|
||||
#include "globalannotationeditor.h"
|
||||
|
||||
#include "annotationeditordialog.h"
|
||||
#include "globalannotationeditordialog.h"
|
||||
#include "annotation.h"
|
||||
|
||||
#include "qmlmodelnodeproxy.h"
|
||||
@@ -49,15 +49,13 @@ GlobalAnnotationEditor::~GlobalAnnotationEditor()
|
||||
|
||||
void GlobalAnnotationEditor::showWidget()
|
||||
{
|
||||
m_dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(),
|
||||
modelNode().validId(),
|
||||
"",
|
||||
m_dialog = new GlobalAnnotationEditorDialog(Core::ICore::dialogParent(),
|
||||
modelNode().globalAnnotation(),
|
||||
AnnotationEditorDialog::EditorMode::GlobalAnnotation);
|
||||
modelNode().globalStatus());
|
||||
|
||||
QObject::connect(m_dialog, &AnnotationEditorDialog::accepted,
|
||||
QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::accepted,
|
||||
this, &GlobalAnnotationEditor::acceptedClicked);
|
||||
QObject::connect(m_dialog, &AnnotationEditorDialog::rejected,
|
||||
QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::rejected,
|
||||
this, &GlobalAnnotationEditor::cancelClicked);
|
||||
|
||||
m_dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
@@ -121,12 +119,24 @@ void GlobalAnnotationEditor::removeFullAnnotation()
|
||||
void GlobalAnnotationEditor::acceptedClicked()
|
||||
{
|
||||
if (m_dialog) {
|
||||
|
||||
Annotation annotation = m_dialog->annotation();
|
||||
|
||||
if (annotation.comments().isEmpty())
|
||||
m_modelNode.removeGlobalAnnotation();
|
||||
else
|
||||
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();
|
||||
|
@@ -29,7 +29,7 @@
|
||||
#include <QtQml>
|
||||
#include <QPointer>
|
||||
|
||||
#include "annotationeditordialog.h"
|
||||
#include "globalannotationeditordialog.h"
|
||||
#include "annotation.h"
|
||||
|
||||
#include "modelnode.h"
|
||||
@@ -67,7 +67,7 @@ private slots:
|
||||
void cancelClicked();
|
||||
|
||||
private:
|
||||
QPointer<AnnotationEditorDialog> m_dialog;
|
||||
QPointer<GlobalAnnotationEditorDialog> m_dialog;
|
||||
|
||||
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>
|