Merge "Merge remote-tracking branch 'origin/qds-1.59'"

This commit is contained in:
The Qt Project
2020-06-08 14:11:10 +00:00
232 changed files with 25313 additions and 9273 deletions

View File

@@ -439,6 +439,17 @@ we thank the authors who made this possible:
Distributed under the Boost Software License, Version 1.0. Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
### Implementation for std::span
https://github.com/tcbrindle/span
QtCreator/src/libs/3rdparty/span
Copyright Tristan Brindle, 2018
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
### Open Source front-end for C++ (license MIT), enhanced for use in Qt Creator ### Open Source front-end for C++ (license MIT), enhanced for use in Qt Creator
Roberto Raggi <roberto.raggi@gmail.com> Roberto Raggi <roberto.raggi@gmail.com>

View File

@@ -182,6 +182,21 @@
\li \l{https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/src/libs/3rdparty/variant} \li \l{https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/src/libs/3rdparty/variant}
\endlist \endlist
\li \b{Implementation for std::span}
Copyright Tristan Brindle, 2018
Distributed under the \l {http://boost.org/LICENSE_1_0.txt}
{Boost Software License, Version 1.0}.
(See accompanying file LICENSE.md.)
The source code can be found here:
\list
\li \l{https://github.com/tcbrindle/span}
\li QtCreator/src/libs/3rdparty/span
\li \l{https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/src/libs/3rdparty/span}
\endlist
\li \b{Open Source front-end for C++ (license MIT)}, enhanced for use \li \b{Open Source front-end for C++ (license MIT)}, enhanced for use
in \QC.\br in \QC.\br
Roberto Raggi <roberto.raggi@gmail.com>\br Roberto Raggi <roberto.raggi@gmail.com>\br

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -42,6 +42,7 @@
\list \list
\li \l{DirectionalLight}{Light Directional} \li \l{DirectionalLight}{Light Directional}
\li \l{PointLight}{Light Point} \li \l{PointLight}{Light Point}
\li \l{SpotLight}{Light Spot}
\li \l{AreaLight}{Light Area} \li \l{AreaLight}{Light Area}
\endlist \endlist
@@ -121,6 +122,22 @@
Aside from fade, a point light has the same properties as a directional Aside from fade, a point light has the same properties as a directional
light. light.
\section1 Spot Light
A spot light emits light towards one direction in a cone shape.
The light intensity diminishes when approaching the value of the
\uicontrol {Cone angle} property. The angle at which the light
intensity starts to diminish is defined by the
\uicontrol {Inner cone angle} property. Both angles are defined in degrees.
Inside the inner cone angle, the spot light behaves similarly to the point
light. There the light intensity diminishes according to inverse-square-law.
However, the fade-off (and range) can be controlled with the
\uicontrol {Constant fade}, \uicontrol {Linear fade}, and
\uicontrol {Quadratic fade} properties.
\image studio-3d-spot-light.png
\section1 Area Light \section1 Area Light
An area light is similar to the directional light. However, instead of An area light is similar to the directional light. However, instead of
@@ -135,7 +152,7 @@
The image below shows an example on how to light an object with different The image below shows an example on how to light an object with different
colors using two different area lights. colors using two different area lights.
\image area-light.png \image studio-3d-area-light.png
You can rotate, scale, and move area lights. You can rotate, scale, and move area lights.

View File

@@ -159,7 +159,7 @@
an easy way to add a high-quality look at a relatively low cost. an easy way to add a high-quality look at a relatively low cost.
To specify an image to use as the specular reflection map, set the To specify an image to use as the specular reflection map, set the
\uicontrol {Light probe} property \uicontrol {Light probe} property.
Crisp images cause your material to look very glossy. The more you Crisp images cause your material to look very glossy. The more you
blur your image, the softer your material appears. blur your image, the softer your material appears.

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -1,6 +1,8 @@
INCLUDEPATH += $$PWD/ INCLUDEPATH += $$PWD/
HEADERS += $$PWD/synchronizecommand.h HEADERS += $$PWD/synchronizecommand.h
HEADERS += $$PWD/changepreviewimagesizecommand.h
HEADERS += $$PWD/changelanguagecommand.h
HEADERS += $$PWD//debugoutputcommand.h HEADERS += $$PWD//debugoutputcommand.h
HEADERS += $$PWD/endpuppetcommand.h HEADERS += $$PWD/endpuppetcommand.h
HEADERS += $$PWD/tokencommand.h HEADERS += $$PWD/tokencommand.h
@@ -33,6 +35,8 @@ HEADERS += $$PWD/inputeventcommand.h
HEADERS += $$PWD/view3dactioncommand.h HEADERS += $$PWD/view3dactioncommand.h
SOURCES += $$PWD/synchronizecommand.cpp SOURCES += $$PWD/synchronizecommand.cpp
SOURCES += $$PWD/changepreviewimagesizecommand.cpp
SOURCES += $$PWD/changelanguagecommand.cpp
SOURCES += $$PWD/debugoutputcommand.cpp SOURCES += $$PWD/debugoutputcommand.cpp
SOURCES += $$PWD/endpuppetcommand.cpp SOURCES += $$PWD/endpuppetcommand.cpp
SOURCES += $$PWD/tokencommand.cpp SOURCES += $$PWD/tokencommand.cpp

View File

@@ -35,43 +35,44 @@
#include "nodeinstanceserverinterface.h" #include "nodeinstanceserverinterface.h"
#include "propertyabstractcontainer.h" #include "changeauxiliarycommand.h"
#include "propertyvaluecontainer.h" #include "changebindingscommand.h"
#include "propertybindingcontainer.h" #include "changefileurlcommand.h"
#include "instancecontainer.h" #include "changeidscommand.h"
#include "changelanguagecommand.h"
#include "changenodesourcecommand.h"
#include "changepreviewimagesizecommand.h"
#include "changeselectioncommand.h"
#include "changestatecommand.h"
#include "changevaluescommand.h"
#include "childrenchangedcommand.h"
#include "clearscenecommand.h"
#include "completecomponentcommand.h"
#include "componentcompletedcommand.h"
#include "createinstancescommand.h" #include "createinstancescommand.h"
#include "createscenecommand.h" #include "createscenecommand.h"
#include "update3dviewstatecommand.h"
#include "changevaluescommand.h"
#include "changebindingscommand.h"
#include "changeauxiliarycommand.h"
#include "changefileurlcommand.h"
#include "removeinstancescommand.h"
#include "clearscenecommand.h"
#include "removepropertiescommand.h"
#include "reparentinstancescommand.h"
#include "changeidscommand.h"
#include "changestatecommand.h"
#include "completecomponentcommand.h"
#include "synchronizecommand.h"
#include "removesharedmemorycommand.h"
#include "tokencommand.h"
#include "inputeventcommand.h"
#include "view3dactioncommand.h"
#include "informationchangedcommand.h"
#include "pixmapchangedcommand.h"
#include "valueschangedcommand.h"
#include "childrenchangedcommand.h"
#include "imagecontainer.h"
#include "statepreviewimagechangedcommand.h"
#include "componentcompletedcommand.h"
#include "changenodesourcecommand.h"
#include "endpuppetcommand.h"
#include "debugoutputcommand.h" #include "debugoutputcommand.h"
#include "endpuppetcommand.h"
#include "imagecontainer.h"
#include "informationchangedcommand.h"
#include "inputeventcommand.h"
#include "instancecontainer.h"
#include "pixmapchangedcommand.h"
#include "propertyabstractcontainer.h"
#include "propertybindingcontainer.h"
#include "propertyvaluecontainer.h"
#include "puppetalivecommand.h" #include "puppetalivecommand.h"
#include "changeselectioncommand.h"
#include "puppettocreatorcommand.h" #include "puppettocreatorcommand.h"
#include "removeinstancescommand.h"
#include "removepropertiescommand.h"
#include "removesharedmemorycommand.h"
#include "reparentinstancescommand.h"
#include "statepreviewimagechangedcommand.h"
#include "synchronizecommand.h"
#include "tokencommand.h"
#include "update3dviewstatecommand.h"
#include "valueschangedcommand.h"
#include "view3dactioncommand.h"
namespace QmlDesigner { namespace QmlDesigner {
@@ -91,7 +92,7 @@ NodeInstanceClientProxy::NodeInstanceClientProxy(QObject *parent)
m_synchronizeId(-1) m_synchronizeId(-1)
{ {
connect(&m_puppetAliveTimer, &QTimer::timeout, this, &NodeInstanceClientProxy::sendPuppetAliveCommand); connect(&m_puppetAliveTimer, &QTimer::timeout, this, &NodeInstanceClientProxy::sendPuppetAliveCommand);
m_puppetAliveTimer.setInterval(1000); m_puppetAliveTimer.setInterval(2000);
m_puppetAliveTimer.start(); m_puppetAliveTimer.start();
} }
@@ -324,6 +325,16 @@ void NodeInstanceClientProxy::view3DAction(const View3DActionCommand &command)
nodeInstanceServer()->view3DAction(command); nodeInstanceServer()->view3DAction(command);
} }
void NodeInstanceClientProxy::changeLanguage(const ChangeLanguageCommand &command)
{
nodeInstanceServer()->changeLanguage(command);
}
void NodeInstanceClientProxy::changePreviewImageSize(const ChangePreviewImageSizeCommand &command)
{
nodeInstanceServer()->changePreviewImageSize(command);
}
void NodeInstanceClientProxy::readDataStream() void NodeInstanceClientProxy::readDataStream()
{ {
QList<QVariant> commandList; QList<QVariant> commandList;
@@ -490,6 +501,9 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command)
static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand"); static const int changeSelectionCommandType = QMetaType::type("ChangeSelectionCommand");
static const int inputEventCommandType = QMetaType::type("InputEventCommand"); static const int inputEventCommandType = QMetaType::type("InputEventCommand");
static const int view3DActionCommandType = QMetaType::type("View3DActionCommand"); static const int view3DActionCommandType = QMetaType::type("View3DActionCommand");
static const int changeLanguageCommand = QMetaType::type("ChangeLanguageCommand");
static const int changePreviewImageSizeCommand = QMetaType::type(
"ChangePreviewImageSizeCommand");
const int commandType = command.userType(); const int commandType = command.userType();
@@ -539,6 +553,10 @@ void NodeInstanceClientProxy::dispatchCommand(const QVariant &command)
} else if (commandType == changeSelectionCommandType) { } else if (commandType == changeSelectionCommandType) {
ChangeSelectionCommand changeSelectionCommand = command.value<ChangeSelectionCommand>(); ChangeSelectionCommand changeSelectionCommand = command.value<ChangeSelectionCommand>();
changeSelection(changeSelectionCommand); changeSelection(changeSelectionCommand);
} else if (command.userType() == changeLanguageCommand) {
changeLanguage(command.value<ChangeLanguageCommand>());
} else if (command.userType() == changePreviewImageSizeCommand) {
changePreviewImageSize(command.value<ChangePreviewImageSizeCommand>());
} else { } else {
Q_ASSERT(false); Q_ASSERT(false);
} }

View File

@@ -61,6 +61,8 @@ class ChangeSelectionCommand;
class PuppetToCreatorCommand; class PuppetToCreatorCommand;
class InputEventCommand; class InputEventCommand;
class View3DActionCommand; class View3DActionCommand;
class ChangeLanguageCommand;
class ChangePreviewImageSizeCommand;
class NodeInstanceClientProxy : public QObject, public NodeInstanceClientInterface class NodeInstanceClientProxy : public QObject, public NodeInstanceClientInterface
{ {
@@ -116,6 +118,8 @@ protected:
static QVariant readCommandFromIOStream(QIODevice *ioDevice, quint32 *readCommandCounter, quint32 *blockSize); static QVariant readCommandFromIOStream(QIODevice *ioDevice, quint32 *readCommandCounter, quint32 *blockSize);
void inputEvent(const InputEventCommand &command); void inputEvent(const InputEventCommand &command);
void view3DAction(const View3DActionCommand &command); void view3DAction(const View3DActionCommand &command);
void changeLanguage(const ChangeLanguageCommand &command);
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command);
protected slots: protected slots:
void readDataStream(); void readDataStream();

View File

@@ -26,44 +26,45 @@
#include "nodeinstanceserverinterface.h" #include "nodeinstanceserverinterface.h"
#include <qmetatype.h> #include <qmetatype.h>
#include "propertyabstractcontainer.h"
#include "propertyvaluecontainer.h"
#include "propertybindingcontainer.h"
#include "instancecontainer.h"
#include "createinstancescommand.h"
#include "createscenecommand.h"
#include "update3dviewstatecommand.h"
#include "changevaluescommand.h"
#include "changebindingscommand.h"
#include "changeauxiliarycommand.h"
#include "changefileurlcommand.h"
#include "removeinstancescommand.h"
#include "clearscenecommand.h"
#include "removepropertiescommand.h"
#include "reparentinstancescommand.h"
#include "changeidscommand.h"
#include "changestatecommand.h"
#include "completecomponentcommand.h"
#include "addimportcontainer.h" #include "addimportcontainer.h"
#include "changeauxiliarycommand.h"
#include "changebindingscommand.h"
#include "changefileurlcommand.h"
#include "changeidscommand.h"
#include "changelanguagecommand.h"
#include "changenodesourcecommand.h" #include "changenodesourcecommand.h"
#include "changeselectioncommand.h" #include "changeselectioncommand.h"
#include "inputeventcommand.h" #include "changestatecommand.h"
#include "view3dactioncommand.h" #include "changevaluescommand.h"
#include "changepreviewimagesizecommand.h"
#include "informationchangedcommand.h"
#include "pixmapchangedcommand.h"
#include "valueschangedcommand.h"
#include "childrenchangedcommand.h" #include "childrenchangedcommand.h"
#include "imagecontainer.h" #include "clearscenecommand.h"
#include "statepreviewimagechangedcommand.h" #include "completecomponentcommand.h"
#include "componentcompletedcommand.h" #include "componentcompletedcommand.h"
#include "synchronizecommand.h" #include "createinstancescommand.h"
#include "tokencommand.h" #include "createscenecommand.h"
#include "removesharedmemorycommand.h"
#include "endpuppetcommand.h"
#include "debugoutputcommand.h" #include "debugoutputcommand.h"
#include "endpuppetcommand.h"
#include "imagecontainer.h"
#include "informationchangedcommand.h"
#include "inputeventcommand.h"
#include "instancecontainer.h"
#include "pixmapchangedcommand.h"
#include "propertyabstractcontainer.h"
#include "propertybindingcontainer.h"
#include "propertyvaluecontainer.h"
#include "puppetalivecommand.h" #include "puppetalivecommand.h"
#include "puppettocreatorcommand.h" #include "puppettocreatorcommand.h"
#include "removeinstancescommand.h"
#include "removepropertiescommand.h"
#include "removesharedmemorycommand.h"
#include "reparentinstancescommand.h"
#include "statepreviewimagechangedcommand.h"
#include "synchronizecommand.h"
#include "tokencommand.h"
#include "update3dviewstatecommand.h"
#include "valueschangedcommand.h"
#include "view3dactioncommand.h"
#include <enumeration.h> #include <enumeration.h>
@@ -212,6 +213,12 @@ void NodeInstanceServerInterface::registerCommands()
qRegisterMetaType<QPair<int, int>>("QPairIntInt"); qRegisterMetaType<QPair<int, int>>("QPairIntInt");
qRegisterMetaTypeStreamOperators<QPair<int, int>>("QPairIntInt"); qRegisterMetaTypeStreamOperators<QPair<int, int>>("QPairIntInt");
qRegisterMetaType<ChangeLanguageCommand>("ChangeLanguageCommand");
qRegisterMetaTypeStreamOperators<ChangeLanguageCommand>("ChangeLanguageCommand");
qRegisterMetaType<ChangePreviewImageSizeCommand>("ChangePreviewImageSizeCommand");
qRegisterMetaTypeStreamOperators<ChangePreviewImageSizeCommand>("ChangePreviewImageSizeCommand");
} }
} }

View File

@@ -53,6 +53,8 @@ class RemoveSharedMemoryCommand;
class ChangeSelectionCommand; class ChangeSelectionCommand;
class InputEventCommand; class InputEventCommand;
class View3DActionCommand; class View3DActionCommand;
class ChangeLanguageCommand;
class ChangePreviewImageSizeCommand;
class NodeInstanceServerInterface : public QObject class NodeInstanceServerInterface : public QObject
{ {
@@ -85,9 +87,10 @@ public:
virtual void changeSelection(const ChangeSelectionCommand &command) = 0; virtual void changeSelection(const ChangeSelectionCommand &command) = 0;
virtual void inputEvent(const InputEventCommand &command) = 0; virtual void inputEvent(const InputEventCommand &command) = 0;
virtual void view3DAction(const View3DActionCommand &command) = 0; virtual void view3DAction(const View3DActionCommand &command) = 0;
virtual void changeLanguage(const ChangeLanguageCommand &command) = 0;
virtual void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) = 0;
virtual void benchmark(const QString &) virtual void benchmark(const QString &) {}
{}
static void registerCommands(); static void registerCommands();
}; };

View File

@@ -69,6 +69,7 @@
#include <changeselectioncommand.h> #include <changeselectioncommand.h>
#include <inputeventcommand.h> #include <inputeventcommand.h>
#include <view3dactioncommand.h> #include <view3dactioncommand.h>
#include <changelanguagecommand.h>
#include <QDebug> #include <QDebug>
#include <QQmlEngine> #include <QQmlEngine>
@@ -1397,7 +1398,22 @@ void NodeInstanceServer::view3DAction(const View3DActionCommand &command)
Q_UNUSED(command) Q_UNUSED(command)
} }
void NodeInstanceServer::changeLanguage(const ChangeLanguageCommand &command)
{
static QPointer<MultiLanguage::Translator> multilanguageTranslator;
if (!MultiLanguage::databaseFilePath().isEmpty()) {
if (!multilanguageLink) {
multilanguageLink = std::make_unique<MultiLanguage::Link>();
multilanguageTranslator = multilanguageLink->translator().release();
QCoreApplication::installTranslator(multilanguageTranslator);
}
if (multilanguageTranslator)
multilanguageTranslator->setLanguage(command.language);
}
QEvent ev(QEvent::LanguageChange);
QCoreApplication::sendEvent(QCoreApplication::instance(), &ev);
engine()->retranslate();
} }
void NodeInstanceServer::changePreviewImageSize(const ChangePreviewImageSizeCommand &) {}
} // namespace QmlDesigner

View File

@@ -25,12 +25,20 @@
#pragma once #pragma once
#include <QDebug>
#include <QUrl> #include <QUrl>
#include <QVector> #include <QVector>
#include <QSet> #include <QSet>
#include <QStringList> #include <QStringList>
#include <QPointer> #include <QPointer>
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
#include <multilanguagelink.h>
#endif
#include <QTranslator>
#include <memory>
#include <nodeinstanceserverinterface.h> #include <nodeinstanceserverinterface.h>
#include "servernodeinstance.h" #include "servernodeinstance.h"
#include "debugoutputcommand.h" #include "debugoutputcommand.h"
@@ -47,6 +55,37 @@ QList<T>toList(const QSet<T> &set)
} }
} //QtHelpers } //QtHelpers
#ifndef MULTILANGUAGE_TRANSLATIONPROVIDER
namespace MultiLanguage {
static QByteArray databaseFilePath()
{
return {};
}
class Translator : public QTranslator
{
public:
void setLanguage(const QString&) {}
};
class Link
{
public:
Link()
{
if (qEnvironmentVariableIsSet("QT_MULTILANGUAGE_DATABASE"))
qWarning() << "QT_MULTILANGUAGE_DATABASE is set but QQmlDebugTranslationService is without MULTILANGUAGE_TRANSLATIONPROVIDER support compiled.";
}
std::unique_ptr<MultiLanguage::Translator> translator() {
//should never be called
Q_ASSERT(false);
return std::make_unique<MultiLanguage::Translator>();
}
const bool isActivated = false;
};
} //namespace MultiLanguage
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QFileSystemWatcher; class QFileSystemWatcher;
class QQmlView; class QQmlView;
@@ -112,6 +151,8 @@ public:
void changeSelection(const ChangeSelectionCommand &command) override; void changeSelection(const ChangeSelectionCommand &command) override;
void inputEvent(const InputEventCommand &command) override; void inputEvent(const InputEventCommand &command) override;
void view3DAction(const View3DActionCommand &command) override; void view3DAction(const View3DActionCommand &command) override;
void changeLanguage(const ChangeLanguageCommand &command) override;
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override;
ServerNodeInstance instanceForId(qint32 id) const; ServerNodeInstance instanceForId(qint32 id) const;
bool hasInstanceForId(qint32 id) const; bool hasInstanceForId(qint32 id) const;
@@ -248,6 +289,7 @@ private:
QPointer<QObject> m_dummyContextObject; QPointer<QObject> m_dummyContextObject;
QPointer<QQmlComponent> m_importComponent; QPointer<QQmlComponent> m_importComponent;
QPointer<QObject> m_importComponentObject; QPointer<QObject> m_importComponentObject;
std::unique_ptr<MultiLanguage::Link> multilanguageLink;
}; };
} }

View File

@@ -768,6 +768,8 @@ QObject *ObjectNodeInstance::createComponent(const QString &componentPath, QQmlC
qWarning() << error; qWarning() << error;
} }
object->setProperty("__designer_url__", QUrl::fromLocalFile(componentPath));
return object; return object;
} }

View File

@@ -25,10 +25,12 @@
#include "qt5previewnodeinstanceserver.h" #include "qt5previewnodeinstanceserver.h"
#include "nodeinstanceclientinterface.h" #include "changepreviewimagesizecommand.h"
#include "statepreviewimagechangedcommand.h"
#include "createscenecommand.h" #include "createscenecommand.h"
#include "nodeinstanceclientinterface.h"
#include "removesharedmemorycommand.h" #include "removesharedmemorycommand.h"
#include "statepreviewimagechangedcommand.h"
#include <QQuickView> #include <QQuickView>
#include <QQuickItem> #include <QQuickItem>
#include <designersupportdelegate.h> #include <designersupportdelegate.h>
@@ -100,7 +102,9 @@ QImage Qt5PreviewNodeInstanceServer::renderPreviewImage()
QRectF boundingRect = rootNodeInstance().boundingRect(); QRectF boundingRect = rootNodeInstance().boundingRect();
QSize previewImageSize = boundingRect.size().toSize(); QSize previewImageSize = boundingRect.size().toSize();
previewImageSize.scale(QSize(160, 160), Qt::KeepAspectRatio);
if (!m_previewSize.isNull())
previewImageSize.scale(m_previewSize, Qt::KeepAspectRatio);
QImage previewImage = rootNodeInstance().renderPreviewImage(previewImageSize); QImage previewImage = rootNodeInstance().renderPreviewImage(previewImageSize);
@@ -113,4 +117,15 @@ void QmlDesigner::Qt5PreviewNodeInstanceServer::removeSharedMemory(const QmlDesi
ImageContainer::removeSharedMemorys(command.keyNumbers()); ImageContainer::removeSharedMemorys(command.keyNumbers());
} }
void Qt5PreviewNodeInstanceServer::changePreviewImageSize(
const ChangePreviewImageSizeCommand &command)
{
m_previewSize = command.size;
if (!command.size.isValid())
m_previewSize = {160, 160};
collectItemChangesAndSendChangeCommands();
}
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -38,6 +38,7 @@ public:
void createScene(const CreateSceneCommand &command) override; void createScene(const CreateSceneCommand &command) override;
void changeState(const ChangeStateCommand &command) override; void changeState(const ChangeStateCommand &command) override;
void removeSharedMemory(const RemoveSharedMemoryCommand &command) override; void removeSharedMemory(const RemoveSharedMemoryCommand &command) override;
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override;
QImage renderPreviewImage(); QImage renderPreviewImage();
@@ -47,6 +48,7 @@ protected:
private: private:
ServerNodeInstance m_currentState; ServerNodeInstance m_currentState;
QSize m_previewSize{160, 160};
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -5,6 +5,13 @@ CONFIG += c++11
DEFINES -= QT_CREATOR DEFINES -= QT_CREATOR
# This .pri file contains classes to enable a special multilanguage translator debug service
MULTILANGUAGE_SUPPORT_PRI=$$(MULTILANGUAGE_SUPPORT_PRI)
!isEmpty(MULTILANGUAGE_SUPPORT_PRI) {
include($$(MULTILANGUAGE_SUPPORT_PRI))
DEFINES += MULTILANGUAGE_TRANSLATIONPROVIDER
}
include (editor3d/editor3d.pri) include (editor3d/editor3d.pri)
include (../instances/instances.pri) include (../instances/instances.pri)
include (instances/instances.pri) include (instances/instances.pri)

View File

@@ -26,6 +26,8 @@
import HelperWidgets 2.0 import HelperWidgets 2.0
import QtQuick 2.1 import QtQuick 2.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import StudioTheme 1.0 as StudioTheme
Section { Section {
id: section id: section
caption: qsTr("Animation") caption: qsTr("Animation")
@@ -33,6 +35,7 @@ Section {
anchors.right: parent.right anchors.right: parent.right
property bool showDuration: true property bool showDuration: true
property bool showEasingCurve: false
SectionLayout { SectionLayout {
Label { Label {
@@ -100,5 +103,22 @@ Section {
text: backendValues.alwaysRunToEnd.valueToString text: backendValues.alwaysRunToEnd.valueToString
backendValue: backendValues.alwaysRunToEnd backendValue: backendValues.alwaysRunToEnd
} }
Label {
visible: section.showEasingCurve
text: qsTr("Easing Curve")
tooltip: qsTr("Define custom easing curve")
}
BoolButtonRowButton {
visible: section.showEasingCurve
buttonIcon: StudioTheme.Constants.curveDesigner
EasingCurveEditor {
id: easingCurveEditor
modelNodeBackendProperty: modelNodeBackend
}
onClicked: easingCurveEditor.runDialog()
}
} }
} }

View File

@@ -57,6 +57,7 @@ Column {
} }
AnimationSection { AnimationSection {
showEasingCurve: true
} }
} }

View File

@@ -325,13 +325,11 @@ Rectangle {
frameVisible: false frameVisible: false
id: tabView id: tabView
height: Math.max(layoutSectionHeight, specficsHeight) height: Math.max(layoutSectionHeight, specficsHeight, advancedHeight) + extraHeight
property int layoutSectionHeight: 400 property int advancedHeight: 0
property int specficsOneHeight: 0 property int layoutSectionHeight: 0
property int specficsTwoHeight: 0 property int specficsHeight: 0
property int specficsHeight: Math.max(specficsOneHeight, specficsTwoHeight)
property int extraHeight: 40 property int extraHeight: 40
@@ -341,6 +339,9 @@ Rectangle {
component: Column { component: Column {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
onImplicitHeightChanged: tabView.specficsHeight = implicitHeight
Loader { Loader {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
@@ -355,13 +356,6 @@ Rectangle {
active = false active = false
active = true active = true
} }
property int loaderHeight: specificsTwo.item.height + tabView.extraHeight
onLoaderHeightChanged: tabView.specficsTwoHeight = loaderHeight
onLoaded: {
tabView.specficsTwoHeight = loaderHeight
}
} }
Loader { Loader {
@@ -387,11 +381,9 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
onImplicitHeightChanged: tabView.layoutSectionHeight = implicitHeight
LayoutSection { LayoutSection {
property int childRectHeight: childrenRect.height
onChildRectHeightChanged: {
tabView.layoutSectionHeight = childRectHeight + tabView.extraHeight
}
} }
MarginSection { MarginSection {
@@ -720,6 +712,9 @@ Rectangle {
component: Column { component: Column {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
onImplicitHeightChanged: tabView.advancedHeight = implicitHeight
AdvancedSection { AdvancedSection {
} }
LayerSection { LayerSection {

View File

@@ -79,6 +79,7 @@ Column {
} }
AnimationSection { AnimationSection {
showEasingCurve: true
} }
} }

View File

@@ -35,6 +35,7 @@ Column {
} }
AnimationSection { AnimationSection {
showEasingCurve: true
} }
} }

View File

@@ -163,4 +163,9 @@ StudioControls.ComboBox {
colorLogic.invalidate() colorLogic.invalidate()
comboBox.__isCompleted = true comboBox.__isCompleted = true
} }
Connections {
target: modelNodeBackend
onSelectionToBeChanged: comboBox.popup.close()
}
} }

View File

@@ -193,7 +193,7 @@ Section {
Layout.fillWidth: true Layout.fillWidth: true
backendValue: getBackendValue("styleName") backendValue: getBackendValue("styleName")
model: styleNamesForFamily(fontComboBox.familyName) model: styleNamesForFamily(fontComboBox.familyName)
useString: true valueType: ComboBox.String
} }
Label { Label {

View File

@@ -36,9 +36,11 @@ ButtonRow {
property alias checked: myAbstractButton.checked property alias checked: myAbstractButton.checked
signal onCheckedChanged() signal onCheckedChanged()
signal clicked
AbstractButton { AbstractButton {
id: myAbstractButton id: myAbstractButton
onCheckedChanged: myButtonRow.onCheckedChanged() onCheckedChanged: myButtonRow.onCheckedChanged()
onClicked: myButtonRow.clicked()
} }
} }

View File

@@ -48,67 +48,73 @@ QtObject {
readonly property string adsClose: "\u0029" readonly property string adsClose: "\u0029"
readonly property string adsDetach: "\u002A" readonly property string adsDetach: "\u002A"
readonly property string adsDropDown: "\u002B" readonly property string adsDropDown: "\u002B"
readonly property string alignBottom: "\u002C" readonly property string aliasAnimated: "\u002C"
readonly property string alignCenterHorizontal: "\u002D" readonly property string aliasProperty: "\u002D"
readonly property string alignCenterVertical: "\u002E" readonly property string alignBottom: "\u002E"
readonly property string alignLeft: "\u002F" readonly property string alignCenterHorizontal: "\u002F"
readonly property string alignRight: "\u0030" readonly property string alignCenterVertical: "\u0030"
readonly property string alignTo: "\u0031" readonly property string alignLeft: "\u0031"
readonly property string alignTop: "\u0032" readonly property string alignRight: "\u0032"
readonly property string anchorBaseline: "\u0033" readonly property string alignTo: "\u0033"
readonly property string anchorBottom: "\u0034" readonly property string alignTop: "\u0034"
readonly property string anchorFill: "\u0035" readonly property string anchorBaseline: "\u0035"
readonly property string anchorLeft: "\u0036" readonly property string anchorBottom: "\u0036"
readonly property string anchorRight: "\u0037" readonly property string anchorFill: "\u0037"
readonly property string anchorTop: "\u0038" readonly property string anchorLeft: "\u0038"
readonly property string annotationBubble: "\u0039" readonly property string anchorRight: "\u0039"
readonly property string annotationDecal: "\u003A" readonly property string anchorTop: "\u003A"
readonly property string centerHorizontal: "\u003B" readonly property string animatedProperty: "\u003B"
readonly property string centerVertical: "\u003C" readonly property string annotationBubble: "\u003C"
readonly property string closeCross: "\u003D" readonly property string annotationDecal: "\u003D"
readonly property string decisionNode: "\u003E" readonly property string assign: "\u003E"
readonly property string deleteColumn: "\u003F" readonly property string centerHorizontal: "\u003F"
readonly property string deleteRow: "\u0040" readonly property string centerVertical: "\u0040"
readonly property string deleteTable: "\u0041" readonly property string closeCross: "\u0041"
readonly property string detach: "\u0042" readonly property string curveDesigner: "\u0042"
readonly property string distributeBottom: "\u0043" readonly property string curveEditor: "\u0043"
readonly property string distributeCenterHorizontal: "\u0044" readonly property string decisionNode: "\u0044"
readonly property string distributeCenterVertical: "\u0045" readonly property string deleteColumn: "\u0045"
readonly property string distributeLeft: "\u0046" readonly property string deleteRow: "\u0046"
readonly property string distributeOriginBottomRight: "\u0047" readonly property string deleteTable: "\u0047"
readonly property string distributeOriginCenter: "\u0048" readonly property string detach: "\u0048"
readonly property string distributeOriginNone: "\u0049" readonly property string distributeBottom: "\u0049"
readonly property string distributeOriginTopLeft: "\u004A" readonly property string distributeCenterHorizontal: "\u004A"
readonly property string distributeRight: "\u004B" readonly property string distributeCenterVertical: "\u004B"
readonly property string distributeSpacingHorizontal: "\u004C" readonly property string distributeLeft: "\u004C"
readonly property string distributeSpacingVertical: "\u004D" readonly property string distributeOriginBottomRight: "\u004D"
readonly property string distributeTop: "\u004E" readonly property string distributeOriginCenter: "\u004E"
readonly property string edit: "\u004F" readonly property string distributeOriginNone: "\u004F"
readonly property string fontStyleBold: "\u0050" readonly property string distributeOriginTopLeft: "\u0050"
readonly property string fontStyleItalic: "\u0051" readonly property string distributeRight: "\u0051"
readonly property string fontStyleStrikethrough: "\u0052" readonly property string distributeSpacingHorizontal: "\u0052"
readonly property string fontStyleUnderline: "\u0053" readonly property string distributeSpacingVertical: "\u0053"
readonly property string mergeCells: "\u0054" readonly property string distributeTop: "\u0054"
readonly property string redo: "\u0055" readonly property string edit: "\u0055"
readonly property string splitColumns: "\u0056" readonly property string fontStyleBold: "\u0056"
readonly property string splitRows: "\u0057" readonly property string fontStyleItalic: "\u0057"
readonly property string startNode: "\u0058" readonly property string fontStyleStrikethrough: "\u0058"
readonly property string testIcon: "\u0059" readonly property string fontStyleUnderline: "\u0059"
readonly property string textAlignBottom: "\u005A" readonly property string mergeCells: "\u005A"
readonly property string textAlignCenter: "\u005B" readonly property string redo: "\u005B"
readonly property string textAlignLeft: "\u005C" readonly property string splitColumns: "\u005C"
readonly property string textAlignMiddle: "\u005D" readonly property string splitRows: "\u005D"
readonly property string textAlignRight: "\u005E" readonly property string startNode: "\u005E"
readonly property string textAlignTop: "\u005F" readonly property string testIcon: "\u005F"
readonly property string textBulletList: "\u0060" readonly property string textAlignBottom: "\u0060"
readonly property string textFullJustification: "\u0061" readonly property string textAlignCenter: "\u0061"
readonly property string textNumberedList: "\u0062" readonly property string textAlignLeft: "\u0062"
readonly property string tickIcon: "\u0063" readonly property string textAlignMiddle: "\u0063"
readonly property string triState: "\u0064" readonly property string textAlignRight: "\u0064"
readonly property string undo: "\u0065" readonly property string textAlignTop: "\u0065"
readonly property string upDownIcon: "\u0066" readonly property string textBulletList: "\u0066"
readonly property string upDownSquare2: "\u0067" readonly property string textFullJustification: "\u0067"
readonly property string wildcard: "\u0068" readonly property string textNumberedList: "\u0068"
readonly property string tickIcon: "\u0069"
readonly property string triState: "\u006A"
readonly property string undo: "\u006B"
readonly property string upDownIcon: "\u006C"
readonly property string upDownSquare2: "\u006D"
readonly property string wildcard: "\u006E"
readonly property font iconFont: Qt.font({ readonly property font iconFont: Qt.font({
"family": controlIcons.name, "family": controlIcons.name,

23
src/libs/3rdparty/span/LICENSE_1_0.txt vendored Normal file
View 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
View File

@@ -0,0 +1,118 @@
[![Standard](https://img.shields.io/badge/c%2B%2B-11/14/17/20-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization)
[![License](https://img.shields.io/badge/license-BSL-blue.svg)](http://www.boost.org/LICENSE_1_0.txt)
[![Build Status](https://travis-ci.org/tcbrindle/span.svg?branch=master)](https://travis-ci.org/tcbrindle/span)
[![Build status](https://ci.appveyor.com/api/projects/status/ow7cj56s108fs439/branch/master?svg=true)](https://ci.appveyor.com/project/tcbrindle/span/branch/master)
[![Try it on godbolt online](https://img.shields.io/badge/on-godbolt-blue.svg)](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
View 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
View 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;
}

View File

@@ -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);
}

View File

@@ -3,7 +3,8 @@ INCLUDEPATH *= $$PWD
HEADERS += $$PWD/sqlite3.h \ HEADERS += $$PWD/sqlite3.h \
$$PWD/sqlite3ext.h $$PWD/sqlite3ext.h
SOURCES += $$PWD/sqlite3.c SOURCES += $$PWD/sqlite3.c \
$$PWD/carray.c
gcc { gcc {
QMAKE_CFLAGS_WARN_ON = -w QMAKE_CFLAGS_WARN_ON = -w

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -322,6 +322,14 @@ struct sqlite3_api_routines {
/* Version 3.28.0 and later */ /* Version 3.28.0 and later */
int (*stmt_isexplain)(sqlite3_stmt*); int (*stmt_isexplain)(sqlite3_stmt*);
int (*value_frombind)(sqlite3_value*); int (*value_frombind)(sqlite3_value*);
/* Version 3.30.0 and later */
int (*drop_modules)(sqlite3*,const char**);
/* Version 3.31.0 and later */
sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
const char *(*uri_key)(const char*,int);
const char *(*filename_database)(const char*);
const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*);
}; };
/* /*
@@ -612,8 +620,16 @@ typedef int (*sqlite3_loadext_entry)(
/* Version 3.26.0 and later */ /* Version 3.26.0 and later */
#define sqlite3_normalized_sql sqlite3_api->normalized_sql #define sqlite3_normalized_sql sqlite3_api->normalized_sql
/* Version 3.28.0 and later */ /* Version 3.28.0 and later */
#define sqlite3_stmt_isexplain sqlite3_api->isexplain #define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
#define sqlite3_value_frombind sqlite3_api->frombind #define sqlite3_value_frombind sqlite3_api->value_frombind
/* Version 3.30.0 and later */
#define sqlite3_drop_modules sqlite3_api->drop_modules
/* Version 3.31.0 and later */
#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
#define sqlite3_uri_key sqlite3_api->uri_key
#define sqlite3_filename_database sqlite3_api->filename_database
#define sqlite3_filename_journal sqlite3_api->filename_journal
#define sqlite3_filename_wal sqlite3_api->filename_wal
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)

View File

@@ -66,7 +66,7 @@ public:
Sqlite::Table table; Sqlite::Table table;
table.setUseIfNotExists(true); table.setUseIfNotExists(true);
table.setName("symbols"); table.setName("symbols");
table.addColumn("symbolId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); table.addColumn("symbolId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
const Sqlite::Column &usrColumn = table.addColumn("usr", Sqlite::ColumnType::Text); const Sqlite::Column &usrColumn = table.addColumn("usr", Sqlite::ColumnType::Text);
const Sqlite::Column &symbolNameColumn = table.addColumn("symbolName", Sqlite::ColumnType::Text); const Sqlite::Column &symbolNameColumn = table.addColumn("symbolName", Sqlite::ColumnType::Text);
const Sqlite::Column &symbolKindColumn = table.addColumn("symbolKind", Sqlite::ColumnType::Integer); const Sqlite::Column &symbolKindColumn = table.addColumn("symbolKind", Sqlite::ColumnType::Integer);
@@ -100,7 +100,7 @@ public:
Sqlite::Table table; Sqlite::Table table;
table.setUseIfNotExists(true); table.setUseIfNotExists(true);
table.setName("sources"); table.setName("sources");
table.addColumn("sourceId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); table.addColumn("sourceId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
const Sqlite::Column &directoryIdColumn = table.addColumn("directoryId", Sqlite::ColumnType::Integer); const Sqlite::Column &directoryIdColumn = table.addColumn("directoryId", Sqlite::ColumnType::Integer);
const Sqlite::Column &sourceNameColumn = table.addColumn("sourceName", Sqlite::ColumnType::Text); const Sqlite::Column &sourceNameColumn = table.addColumn("sourceName", Sqlite::ColumnType::Text);
table.addUniqueIndex({directoryIdColumn, sourceNameColumn}); table.addUniqueIndex({directoryIdColumn, sourceNameColumn});
@@ -113,7 +113,7 @@ public:
Sqlite::Table table; Sqlite::Table table;
table.setUseIfNotExists(true); table.setUseIfNotExists(true);
table.setName("directories"); table.setName("directories");
table.addColumn("directoryId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); table.addColumn("directoryId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
const Sqlite::Column &directoryPathColumn = table.addColumn("directoryPath", Sqlite::ColumnType::Text); const Sqlite::Column &directoryPathColumn = table.addColumn("directoryPath", Sqlite::ColumnType::Text);
table.addUniqueIndex({directoryPathColumn}); table.addUniqueIndex({directoryPathColumn});
@@ -125,7 +125,7 @@ public:
Sqlite::Table table; Sqlite::Table table;
table.setUseIfNotExists(true); table.setUseIfNotExists(true);
table.setName("projectParts"); table.setName("projectParts");
table.addColumn("projectPartId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); table.addColumn("projectPartId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
const Sqlite::Column &projectPartNameColumn = table.addColumn("projectPartName", Sqlite::ColumnType::Text); const Sqlite::Column &projectPartNameColumn = table.addColumn("projectPartName", Sqlite::ColumnType::Text);
table.addColumn("toolChainArguments", Sqlite::ColumnType::Text); table.addColumn("toolChainArguments", Sqlite::ColumnType::Text);
table.addColumn("compilerMacros", Sqlite::ColumnType::Text); table.addColumn("compilerMacros", Sqlite::ColumnType::Text);
@@ -160,7 +160,7 @@ public:
Sqlite::Table table; Sqlite::Table table;
table.setUseIfNotExists(true); table.setUseIfNotExists(true);
table.setName("usedMacros"); table.setName("usedMacros");
table.addColumn("usedMacroId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); table.addColumn("usedMacroId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer); const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
const Sqlite::Column &macroNameColumn = table.addColumn("macroName", Sqlite::ColumnType::Text); const Sqlite::Column &macroNameColumn = table.addColumn("macroName", Sqlite::ColumnType::Text);
table.addIndex({sourceIdColumn, macroNameColumn}); table.addIndex({sourceIdColumn, macroNameColumn});
@@ -174,9 +174,7 @@ public:
Sqlite::Table table; Sqlite::Table table;
table.setUseIfNotExists(true); table.setUseIfNotExists(true);
table.setName("fileStatuses"); table.setName("fileStatuses");
table.addColumn("sourceId", table.addColumn("sourceId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
Sqlite::ColumnType::Integer,
Sqlite::Contraint::PrimaryKey);
table.addColumn("size", Sqlite::ColumnType::Integer); table.addColumn("size", Sqlite::ColumnType::Integer);
table.addColumn("lastModified", Sqlite::ColumnType::Integer); table.addColumn("lastModified", Sqlite::ColumnType::Integer);
table.addColumn("indexingTimeStamp", Sqlite::ColumnType::Integer); table.addColumn("indexingTimeStamp", Sqlite::ColumnType::Integer);
@@ -201,7 +199,7 @@ public:
Sqlite::Table table; Sqlite::Table table;
table.setUseIfNotExists(true); table.setUseIfNotExists(true);
table.setName("precompiledHeaders"); table.setName("precompiledHeaders");
table.addColumn("projectPartId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); table.addColumn("projectPartId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
table.addColumn("projectPchPath", Sqlite::ColumnType::Text); table.addColumn("projectPchPath", Sqlite::ColumnType::Text);
table.addColumn("projectPchBuildTime", Sqlite::ColumnType::Integer); table.addColumn("projectPchBuildTime", Sqlite::ColumnType::Integer);
table.addColumn("systemPchPath", Sqlite::ColumnType::Text); table.addColumn("systemPchPath", Sqlite::ColumnType::Text);

View File

@@ -53,7 +53,7 @@ inline QString qmlDebugServices(QmlDebugServicesPreset preset)
case QmlNativeDebuggerServices: case QmlNativeDebuggerServices:
return QStringLiteral("NativeQmlDebugger"); return QStringLiteral("NativeQmlDebugger");
case QmlPreviewServices: case QmlPreviewServices:
return QStringLiteral("QmlPreview"); return QStringLiteral("QmlPreview,DebugTranslation");
default: default:
Q_ASSERT(false); Q_ASSERT(false);
return QString(); return QString();

View File

@@ -942,6 +942,9 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
if (checkTypeForDesignerSupport(typeId)) if (checkTypeForDesignerSupport(typeId))
addMessage(WarnUnsupportedTypeInVisualDesigner, typeErrorLocation, typeName); addMessage(WarnUnsupportedTypeInVisualDesigner, typeErrorLocation, typeName);
if (QFileInfo(_doc->fileName()).baseName() == getRightMostIdentifier(typeId)->name.toString())
addMessage(ErrTypeIsInstantiatedRecursively, typeErrorLocation, typeName);
if (checkTypeForQmlUiSupport(typeId)) if (checkTypeForQmlUiSupport(typeId))
addMessage(ErrUnsupportedTypeInQmlUi, typeErrorLocation, typeName); addMessage(ErrUnsupportedTypeInQmlUi, typeErrorLocation, typeName);

View File

@@ -245,6 +245,8 @@ StaticAnalysisMessages::StaticAnalysisMessages()
tr("Duplicate import (%1)."), 1); tr("Duplicate import (%1)."), 1);
newMsg(ErrHitMaximumRecursion, Error, newMsg(ErrHitMaximumRecursion, Error,
tr("Hit maximum recursion limit when visiting AST.")); tr("Hit maximum recursion limit when visiting AST."));
newMsg(ErrTypeIsInstantiatedRecursively, Error,
tr("Type cannot be instantiated recursively (%1)."), 1);
} }
} // anonymous namespace } // anonymous namespace

View File

@@ -89,6 +89,7 @@ enum Type
MaybeWarnEqualityTypeCoercion = 126, MaybeWarnEqualityTypeCoercion = 126,
WarnConfusingExpressionStatement = 127, WarnConfusingExpressionStatement = 127,
StateCannotHaveChildItem = 128, StateCannotHaveChildItem = 128,
ErrTypeIsInstantiatedRecursively = 129,
HintDeclarationsShouldBeAtStartOfFunction = 201, HintDeclarationsShouldBeAtStartOfFunction = 201,
HintOneStatementPerLine = 202, HintOneStatementPerLine = 202,
WarnImperativeCodeNotEditableInVisualDesigner = 203, WarnImperativeCodeNotEditableInVisualDesigner = 203,

View File

@@ -1,15 +1,26 @@
add_qtc_library(Sqlite add_qtc_library(Sqlite
DEFINES PUBLIC_DEFINES
SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS3_PARENTHESIS
SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_COLUMN_METADATA
BUILD_SQLITE_LIBRARY BUILD_SQLITE_LIBRARY
SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS5 SQLITE_ENABLE_UNLOCK_NOTIFY
SQLITE_ENABLE_JSON1 SQLITE_DEFAULT_FOREIGN_KEYS=1 SQLITE_TEMP_STORE=2
SQLITE_DEFAULT_WAL_SYNCHRONOUS=1 SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_MEMSTATUS=0
SQLITE_OMIT_DEPRECATED SQLITE_OMIT_DECLTYPE
SQLITE_MAX_EXPR_DEPTH=0 SQLITE_OMIT_SHARED_CACHE SQLITE_USE_ALLOCA
SQLITE_ENABLE_MEMORY_MANAGEMENT SQLITE_ENABLE_NULL_TRIM SQLITE_OMIT_EXPLAIN
SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_UTF16 SQLITE_DQS=0
SQLITE_ENABLE_STAT4 HAVE_ISNAN HAVE_FDATASYNC HAVE_MALLOC_USABLE_SIZE
SQLITE_DEFAULT_MMAP_SIZE=268435456 SQLITE_CORE SQLITE_ENABLE_SESSION SQLITE_ENABLE_PREUPDATE_HOOK
SQLITE_LIKE_DOESNT_MATCH_BLOBS
DEPENDS Qt5::Core Threads::Threads ${CMAKE_DL_LIBS} DEPENDS Qt5::Core Threads::Threads ${CMAKE_DL_LIBS}
PUBLIC_INCLUDES PUBLIC_INCLUDES
"${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_CURRENT_LIST_DIR}"
../3rdparty/sqlite ../3rdparty/sqlite
SOURCES SOURCES
../3rdparty/sqlite/sqlite3.c ../3rdparty/sqlite/sqlite3.c
../3rdparty/sqlite/carray.c
constraints.h
createtablesqlstatementbuilder.cpp createtablesqlstatementbuilder.h createtablesqlstatementbuilder.cpp createtablesqlstatementbuilder.h
lastchangedrowid.h
sqlitebasestatement.cpp sqlitebasestatement.h sqlitebasestatement.cpp sqlitebasestatement.h
sqlitecolumn.h sqlitecolumn.h
sqlitedatabase.cpp sqlitedatabase.h sqlitedatabase.cpp sqlitedatabase.h
@@ -19,6 +30,8 @@ add_qtc_library(Sqlite
sqliteindex.h sqliteindex.h
sqlitereadstatement.cpp sqlitereadstatement.h sqlitereadstatement.cpp sqlitereadstatement.h
sqlitereadwritestatement.cpp sqlitereadwritestatement.h sqlitereadwritestatement.cpp sqlitereadwritestatement.h
sqlitesessionchangeset.cpp sqlitesessionchangeset.h
sqlitesessions.cpp sqlitesessions.h
sqlitetable.h sqlitetable.h
sqlitetransaction.h sqlitetransaction.h
sqlitewritestatement.cpp sqlitewritestatement.h sqlitewritestatement.cpp sqlitewritestatement.h

View 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

View File

@@ -39,16 +39,26 @@ void CreateTableSqlStatementBuilder::setTableName(Utils::SmallString &&tableName
this->m_tableName = std::move(tableName); this->m_tableName = std::move(tableName);
} }
void CreateTableSqlStatementBuilder::addColumn(Utils::SmallString &&columnName, void CreateTableSqlStatementBuilder::addColumn(Utils::SmallStringView columnName,
ColumnType columnType, ColumnType columnType,
Contraint constraint) Constraints &&constraints)
{ {
m_sqlStatementBuilder.clear(); m_sqlStatementBuilder.clear();
m_columns.emplace_back(std::move(columnName), columnType, constraint); m_columns.emplace_back(Utils::SmallStringView{}, columnName, columnType, std::move(constraints));
} }
void CreateTableSqlStatementBuilder::setColumns(const SqliteColumns &columns) void CreateTableSqlStatementBuilder::addConstraint(TableConstraint &&constraint)
{
m_tableConstraints.push_back(std::move(constraint));
}
void CreateTableSqlStatementBuilder::setConstraints(TableConstraints constraints)
{
m_tableConstraints = std::move(constraints);
}
void CreateTableSqlStatementBuilder::setColumns(SqliteColumns columns)
{ {
m_sqlStatementBuilder.clear(); m_sqlStatementBuilder.clear();
@@ -97,20 +107,162 @@ bool CreateTableSqlStatementBuilder::isValid() const
return m_tableName.hasContent() && !m_columns.empty(); return m_tableName.hasContent() && !m_columns.empty();
} }
void CreateTableSqlStatementBuilder::bindColumnDefinitions() const namespace {
Utils::SmallStringView actionToText(ForeignKeyAction action)
{ {
Utils::SmallStringVector columnDefinitionStrings; switch (action) {
case ForeignKeyAction::NoAction:
for (const Column &columns : m_columns) { return "NO ACTION";
Utils::SmallString columnDefinitionString = {columns.name(), " ", columns.typeString()}; case ForeignKeyAction::Restrict:
return "RESTRICT";
switch (columns.constraint()) { case ForeignKeyAction::SetNull:
case Contraint::PrimaryKey: columnDefinitionString.append(" PRIMARY KEY"); break; return "SET NULL";
case Contraint::Unique: columnDefinitionString.append(" UNIQUE"); break; case ForeignKeyAction::SetDefault:
case Contraint::NoConstraint: break; return "SET DEFAULT";
case ForeignKeyAction::Cascade:
return "CASCADE";
} }
columnDefinitionStrings.push_back(columnDefinitionString); return "";
}
class ContraintsVisiter
{
public:
ContraintsVisiter(Utils::SmallString &columnDefinitionString)
: columnDefinitionString(columnDefinitionString)
{}
void operator()(const Unique &) { columnDefinitionString.append(" UNIQUE"); }
void operator()(const PrimaryKey &primaryKey)
{
columnDefinitionString.append(" PRIMARY KEY");
if (primaryKey.autoincrement == AutoIncrement::Yes)
columnDefinitionString.append(" AUTOINCREMENT");
}
void operator()(const ForeignKey &foreignKey)
{
columnDefinitionString.append(" REFERENCES ");
columnDefinitionString.append(foreignKey.table);
if (foreignKey.column.hasContent()) {
columnDefinitionString.append("(");
columnDefinitionString.append(foreignKey.column);
columnDefinitionString.append(")");
}
if (foreignKey.updateAction != ForeignKeyAction::NoAction) {
columnDefinitionString.append(" ON UPDATE ");
columnDefinitionString.append(actionToText(foreignKey.updateAction));
}
if (foreignKey.deleteAction != ForeignKeyAction::NoAction) {
columnDefinitionString.append(" ON DELETE ");
columnDefinitionString.append(actionToText(foreignKey.deleteAction));
}
if (foreignKey.enforcement == Enforment::Deferred)
columnDefinitionString.append(" DEFERRABLE INITIALLY DEFERRED");
}
void operator()(const NotNull &) { columnDefinitionString.append(" NOT NULL"); }
void operator()(const Check &check)
{
columnDefinitionString.append(" CHECK (");
columnDefinitionString.append(check.expression);
columnDefinitionString.append(")");
}
void operator()(const DefaultValue &defaultValue)
{
columnDefinitionString.append(" DEFAULT ");
switch (defaultValue.value.type()) {
case Sqlite::ValueType::Integer:
columnDefinitionString.append(
Utils::SmallString::number(defaultValue.value.toInteger()));
break;
case Sqlite::ValueType::Float:
columnDefinitionString.append(Utils::SmallString::number(defaultValue.value.toFloat()));
break;
case Sqlite::ValueType::String:
columnDefinitionString.append("'");
columnDefinitionString.append(defaultValue.value.toStringView());
columnDefinitionString.append("'");
break;
}
}
void operator()(const DefaultExpression &defaultexpression)
{
columnDefinitionString.append(" DEFAULT (");
columnDefinitionString.append(defaultexpression.expression);
columnDefinitionString.append(")");
}
void operator()(const Collate &collate)
{
columnDefinitionString.append(" COLLATE ");
columnDefinitionString.append(collate.collation);
}
void operator()(const GeneratedAlways &generatedAlways)
{
columnDefinitionString.append(" GENERATED ALWAYS AS (");
columnDefinitionString.append(generatedAlways.expression);
columnDefinitionString.append(")");
if (generatedAlways.storage == Sqlite::GeneratedAlwaysStorage::Virtual)
columnDefinitionString.append(" VIRTUAL");
else
columnDefinitionString.append(" STORED");
}
Utils::SmallString &columnDefinitionString;
};
class TableContraintsVisiter
{
public:
TableContraintsVisiter(Utils::SmallString &columnDefinitionString)
: columnDefinitionString(columnDefinitionString)
{}
void operator()(const TablePrimaryKey &primaryKey)
{
columnDefinitionString.append("PRIMARY KEY(");
columnDefinitionString.append(primaryKey.columns.join(", "));
columnDefinitionString.append(")");
}
Utils::SmallString &columnDefinitionString;
};
} // namespace
void CreateTableSqlStatementBuilder::bindColumnDefinitionsAndTableConstraints() const
{
Utils::SmallStringVector columnDefinitionStrings;
columnDefinitionStrings.reserve(m_columns.size());
for (const Column &column : m_columns) {
Utils::SmallString columnDefinitionString = {column.name, " ", column.typeString()};
ContraintsVisiter visiter{columnDefinitionString};
for (const Constraint &constraint : column.constraints)
Utils::visit(visiter, constraint);
columnDefinitionStrings.push_back(std::move(columnDefinitionString));
}
for (const TableConstraint &constraint : m_tableConstraints) {
Utils::SmallString columnDefinitionString;
TableContraintsVisiter visiter{columnDefinitionString};
Utils::visit(visiter, constraint);
columnDefinitionStrings.push_back(std::move(columnDefinitionString));
} }
m_sqlStatementBuilder.bind("$columnDefinitions", columnDefinitionStrings); m_sqlStatementBuilder.bind("$columnDefinitions", columnDefinitionStrings);
@@ -122,7 +274,7 @@ void CreateTableSqlStatementBuilder::bindAll() const
bindTemporary(); bindTemporary();
bindIfNotExists(); bindIfNotExists();
bindColumnDefinitions(); bindColumnDefinitionsAndTableConstraints();
bindWithoutRowId(); bindWithoutRowId();
} }

View File

@@ -27,6 +27,7 @@
#include "sqlitecolumn.h" #include "sqlitecolumn.h"
#include "sqlstatementbuilder.h" #include "sqlstatementbuilder.h"
#include "tableconstraints.h"
namespace Sqlite { namespace Sqlite {
@@ -36,10 +37,13 @@ public:
CreateTableSqlStatementBuilder(); CreateTableSqlStatementBuilder();
void setTableName(Utils::SmallString &&tableName); void setTableName(Utils::SmallString &&tableName);
void addColumn(Utils::SmallString &&columnName,
void addColumn(Utils::SmallStringView columnName,
ColumnType columnType, ColumnType columnType,
Contraint constraint = Contraint::NoConstraint); Constraints &&constraints = {});
void setColumns(const SqliteColumns &columns); void addConstraint(TableConstraint &&constraint);
void setConstraints(TableConstraints constraints);
void setColumns(SqliteColumns columns);
void setUseWithoutRowId(bool useWithoutRowId); void setUseWithoutRowId(bool useWithoutRowId);
void setUseIfNotExists(bool useIfNotExists); void setUseIfNotExists(bool useIfNotExists);
void setUseTemporaryTable(bool useTemporaryTable); void setUseTemporaryTable(bool useTemporaryTable);
@@ -52,7 +56,7 @@ public:
bool isValid() const; bool isValid() const;
protected: protected:
void bindColumnDefinitions() const; void bindColumnDefinitionsAndTableConstraints() const;
void bindAll() const; void bindAll() const;
void bindWithoutRowId() const; void bindWithoutRowId() const;
void bindIfNotExists() const; void bindIfNotExists() const;
@@ -62,6 +66,7 @@ private:
mutable SqlStatementBuilder m_sqlStatementBuilder; mutable SqlStatementBuilder m_sqlStatementBuilder;
Utils::SmallString m_tableName; Utils::SmallString m_tableName;
SqliteColumns m_columns; SqliteColumns m_columns;
TableConstraints m_tableConstraints;
bool m_useWithoutRowId = false; bool m_useWithoutRowId = false;
bool m_useIfNotExits = false; bool m_useIfNotExits = false;
bool m_useTemporaryTable = false; bool m_useTemporaryTable = false;

View 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

View File

@@ -17,6 +17,8 @@ SOURCES += \
$$PWD/sqliteglobal.cpp \ $$PWD/sqliteglobal.cpp \
$$PWD/sqlitereadstatement.cpp \ $$PWD/sqlitereadstatement.cpp \
$$PWD/sqlitereadwritestatement.cpp \ $$PWD/sqlitereadwritestatement.cpp \
$$PWD/sqlitesessionchangeset.cpp \
$$PWD/sqlitesessions.cpp \
$$PWD/sqlitewritestatement.cpp \ $$PWD/sqlitewritestatement.cpp \
$$PWD/sqlstatementbuilder.cpp \ $$PWD/sqlstatementbuilder.cpp \
$$PWD/utf8string.cpp \ $$PWD/utf8string.cpp \
@@ -24,13 +26,18 @@ SOURCES += \
$$PWD/sqlitedatabase.cpp \ $$PWD/sqlitedatabase.cpp \
$$PWD/sqlitebasestatement.cpp $$PWD/sqlitebasestatement.cpp
HEADERS += \ HEADERS += \
$$PWD/constraints.h \
$$PWD/tableconstraints.h \
$$PWD/createtablesqlstatementbuilder.h \ $$PWD/createtablesqlstatementbuilder.h \
$$PWD/lastchangedrowid.h \
$$PWD/sqlitedatabasebackend.h \ $$PWD/sqlitedatabasebackend.h \
$$PWD/sqlitedatabaseinterface.h \ $$PWD/sqlitedatabaseinterface.h \
$$PWD/sqliteexception.h \ $$PWD/sqliteexception.h \
$$PWD/sqliteglobal.h \ $$PWD/sqliteglobal.h \
$$PWD/sqlitereadstatement.h \ $$PWD/sqlitereadstatement.h \
$$PWD/sqlitereadwritestatement.h \ $$PWD/sqlitereadwritestatement.h \
$$PWD/sqlitesessionchangeset.h \
$$PWD/sqlitesessions.h \
$$PWD/sqlitetransaction.h \ $$PWD/sqlitetransaction.h \
$$PWD/sqlitevalue.h \ $$PWD/sqlitevalue.h \
$$PWD/sqlitewritestatement.h \ $$PWD/sqlitewritestatement.h \
@@ -44,8 +51,18 @@ HEADERS += \
$$PWD/sqliteindex.h \ $$PWD/sqliteindex.h \
$$PWD/sqlitebasestatement.h $$PWD/sqlitebasestatement.h
DEFINES += SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS3_PARENTHESIS \ DEFINES += SQLITE_THREADSAFE=2 SQLITE_ENABLE_FTS5 SQLITE_ENABLE_UNLOCK_NOTIFY \
SQLITE_ENABLE_UNLOCK_NOTIFY SQLITE_ENABLE_COLUMN_METADATA SQLITE_ENABLE_JSON1 SQLITE_ENABLE_JSON1 SQLITE_DEFAULT_FOREIGN_KEYS=1 SQLITE_TEMP_STORE=2 \
SQLITE_DEFAULT_WAL_SYNCHRONOUS=1 SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_MEMSTATUS=0 \
SQLITE_OMIT_DEPRECATED SQLITE_OMIT_DECLTYPE \
SQLITE_MAX_EXPR_DEPTH=0 SQLITE_OMIT_SHARED_CACHE SQLITE_USE_ALLOCA \
SQLITE_ENABLE_MEMORY_MANAGEMENT SQLITE_ENABLE_NULL_TRIM SQLITE_OMIT_EXPLAIN \
SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_UTF16 SQLITE_DQS=0 \
SQLITE_ENABLE_STAT4 HAVE_ISNAN HAVE_FDATASYNC HAVE_MALLOC_USABLE_SIZE \
SQLITE_DEFAULT_MMAP_SIZE=268435456 SQLITE_CORE SQLITE_ENABLE_SESSION SQLITE_ENABLE_PREUPDATE_HOOK \
SQLITE_LIKE_DOESNT_MATCH_BLOBS
CONFIG(debug, debug|release): DEFINES += SQLITE_ENABLE_API_ARMOR
OTHER_FILES += README.md OTHER_FILES += README.md

View File

@@ -3,7 +3,5 @@ win32:QMAKE_CXXFLAGS_DEBUG += -O2
include(../../qtcreatorlibrary.pri) include(../../qtcreatorlibrary.pri)
win32:DEFINES += SQLITE_API=__declspec(dllexport)
unix:DEFINES += SQLITE_API=\"__attribute__((visibility(\\\"default\\\")))\"
include(sqlite-lib.pri) include(sqlite-lib.pri)

View File

@@ -6,12 +6,16 @@ QtcLibrary {
cpp.includePaths: base.concat(["../3rdparty/sqlite", "."]) cpp.includePaths: base.concat(["../3rdparty/sqlite", "."])
cpp.defines: base.concat([ cpp.defines: base.concat([
"BUILD_SQLITE_LIBRARY", "BUILD_SQLITE_LIBRARY",
"SQLITE_THREADSAFE=2", "SQLITE_THREADSAFE=2", "SQLITE_ENABLE_FTS5", "SQLITE_ENABLE_UNLOCK_NOTIFY",
"SQLITE_ENABLE_FTS4", "SQLITE_ENABLE_JSON1", "SQLITE_DEFAULT_FOREIGN_KEYS=1", "SQLITE_TEMP_STORE=2",
"SQLITE_ENABLE_FTS3_PARENTHESIS", "SQLITE_DEFAULT_WAL_SYNCHRONOUS=1", "SQLITE_MAX_WORKER_THREADS", "SQLITE_DEFAULT_MEMSTATUS=0",
"SQLITE_ENABLE_UNLOCK_NOTIFY", "SQLITE_OMIT_DEPRECATED", "SQLITE_OMIT_DECLTYPE",
"SQLITE_ENABLE_COLUMN_METADATA", "SQLITE_MAX_EXPR_DEPTH=0", "SQLITE_OMIT_SHARED_CACHE", "SQLITE_USE_ALLOCA",
"SQLITE_ENABLE_JSON1" "SQLITE_ENABLE_MEMORY_MANAGEMENT", "SQLITE_ENABLE_NULL_TRIM", "SQLITE_OMIT_EXPLAIN",
"SQLITE_OMIT_LOAD_EXTENSION", "SQLITE_OMIT_UTF16", "SQLITE_DQS=0",
"SQLITE_ENABLE_STAT4", "HAVE_ISNAN", "HAVE_FDATASYNC", "HAVE_MALLOC_USABLE_SIZE",
"SQLITE_DEFAULT_MMAP_SIZE=268435456", "SQLITE_CORE", "SQLITE_ENABLE_SESSION", "SQLITE_ENABLE_PREUPDATE_HOOK",
"SQLITE_LIKE_DOESNT_MATCH_BLOBS"
]) ])
cpp.optimization: "fast" cpp.optimization: "fast"
cpp.dynamicLibraries: base.concat((qbs.targetOS.contains("unix") && !qbs.targetOS.contains("bsd")) cpp.dynamicLibraries: base.concat((qbs.targetOS.contains("unix") && !qbs.targetOS.contains("bsd"))
@@ -26,6 +30,7 @@ QtcLibrary {
"sqlite3.c", "sqlite3.c",
"sqlite3.h", "sqlite3.h",
"sqlite3ext.h", "sqlite3ext.h",
"carray.c"
] ]
} }

View File

@@ -41,11 +41,10 @@
namespace Sqlite { namespace Sqlite {
BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database) BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database)
: m_compiledStatement(nullptr, deleteCompiledStatement), : m_compiledStatement(nullptr, deleteCompiledStatement)
m_database(database), , m_database(database)
m_bindingParameterCount(0), , m_bindingParameterCount(0)
m_columnCount(0), , m_columnCount(0)
m_isReadyToFetchValues(false)
{ {
prepare(sqlStatement); prepare(sqlStatement);
setBindingParameterCount(); setBindingParameterCount();
@@ -107,11 +106,8 @@ void BaseStatement::reset() const
{ {
int resultCode = sqlite3_reset(m_compiledStatement.get()); int resultCode = sqlite3_reset(m_compiledStatement.get());
if (resultCode != SQLITE_OK) { if (resultCode != SQLITE_OK)
checkForResetError(resultCode); checkForResetError(resultCode);
m_isReadyToFetchValues = false;
}
} }
bool BaseStatement::next() const bool BaseStatement::next() const
@@ -127,8 +123,6 @@ bool BaseStatement::next() const
} while (resultCode == SQLITE_LOCKED); } while (resultCode == SQLITE_LOCKED);
setIfIsReadyToFetchValues(resultCode);
if (resultCode == SQLITE_ROW) if (resultCode == SQLITE_ROW)
return true; return true;
else if (resultCode == SQLITE_DONE) else if (resultCode == SQLITE_DONE)
@@ -147,15 +141,11 @@ int BaseStatement::columnCount() const
return m_columnCount; return m_columnCount;
} }
Utils::SmallStringVector BaseStatement::columnNames() const void BaseStatement::bind(int index, NullValue)
{ {
Utils::SmallStringVector columnNames; int resultCode = sqlite3_bind_null(m_compiledStatement.get(), index);
int columnCount = BaseStatement::columnCount(); if (resultCode != SQLITE_OK)
columnNames.reserve(std::size_t(columnCount)); checkForBindingError(resultCode);
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
columnNames.emplace_back(sqlite3_column_origin_name(m_compiledStatement.get(), columnIndex));
return columnNames;
} }
void BaseStatement::bind(int index, int value) void BaseStatement::bind(int index, int value)
@@ -179,6 +169,17 @@ void BaseStatement::bind(int index, double value)
checkForBindingError(resultCode); checkForBindingError(resultCode);
} }
void BaseStatement::bind(int index, void *pointer)
{
int resultCode = sqlite3_bind_pointer(m_compiledStatement.get(),
index,
pointer,
"carray",
nullptr);
if (resultCode != SQLITE_OK)
checkForBindingError(resultCode);
}
void BaseStatement::bind(int index, Utils::SmallStringView text) void BaseStatement::bind(int index, Utils::SmallStringView text)
{ {
int resultCode = sqlite3_bind_text(m_compiledStatement.get(), int resultCode = sqlite3_bind_text(m_compiledStatement.get(),
@@ -190,6 +191,17 @@ void BaseStatement::bind(int index, Utils::SmallStringView text)
checkForBindingError(resultCode); checkForBindingError(resultCode);
} }
void BaseStatement::bind(int index, Utils::span<const byte> bytes)
{
int resultCode = sqlite3_bind_blob64(m_compiledStatement.get(),
index,
bytes.data(),
static_cast<long long>(bytes.size()),
SQLITE_STATIC);
if (resultCode != SQLITE_OK)
checkForBindingError(resultCode);
}
void BaseStatement::bind(int index, const Value &value) void BaseStatement::bind(int index, const Value &value)
{ {
switch (value.type()) { switch (value.type()) {
@@ -205,25 +217,6 @@ void BaseStatement::bind(int index, const Value &value)
} }
} }
template <typename Type>
void BaseStatement::bind(Utils::SmallStringView name, Type value)
{
int index = bindingIndexForName(name);
checkBindingName(index);
bind(index, value);
}
template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, int value);
template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long value);
template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long long value);
template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, double value);
template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text);
int BaseStatement::bindingIndexForName(Utils::SmallStringView name) const
{
return sqlite3_bind_parameter_index(m_compiledStatement.get(), name.data());
}
void BaseStatement::prepare(Utils::SmallStringView sqlStatement) void BaseStatement::prepare(Utils::SmallStringView sqlStatement)
{ {
int resultCode; int resultCode;
@@ -252,11 +245,6 @@ sqlite3 *BaseStatement::sqliteDatabaseHandle() const
return m_database.backend().sqliteDatabaseHandle(); return m_database.backend().sqliteDatabaseHandle();
} }
TextEncoding BaseStatement::databaseTextEncoding()
{
return m_database.backend().textEncoding();
}
void BaseStatement::checkForStepError(int resultCode) const void BaseStatement::checkForStepError(int resultCode) const
{ {
switch (resultCode) { switch (resultCode) {
@@ -305,33 +293,10 @@ void BaseStatement::checkForBindingError(int resultCode) const
throwUnknowError("SqliteStatement::bind: unknown error has happened"); throwUnknowError("SqliteStatement::bind: unknown error has happened");
} }
void BaseStatement::setIfIsReadyToFetchValues(int resultCode) const void BaseStatement::checkColumnCount(int columnCount) const
{ {
if (resultCode == SQLITE_ROW) if (columnCount != m_columnCount)
m_isReadyToFetchValues = true; throw ColumnCountDoesNotMatch("SqliteStatement::values: column count does not match!");
else
m_isReadyToFetchValues = false;
}
void BaseStatement::checkIfIsReadyToFetchValues() const
{
if (!m_isReadyToFetchValues)
throwNoValuesToFetch("SqliteStatement::value: there are no values to fetch!");
}
void BaseStatement::checkColumnsAreValid(const std::vector<int> &columns) const
{
for (int column : columns) {
if (column < 0 || column >= m_columnCount)
throwInvalidColumnFetched("SqliteStatement::values: column index out of bound!");
}
}
void BaseStatement::checkColumnIsValid(int column) const
{
if (column < 0 || column >= m_columnCount)
throwInvalidColumnFetched("SqliteStatement::values: column index out of bound!");
} }
void BaseStatement::checkBindingName(int index) const void BaseStatement::checkBindingName(int index) const
@@ -393,11 +358,6 @@ void BaseStatement::throwNoValuesToFetch(const char *whatHasHappened) const
throw NoValuesToFetch(whatHasHappened); throw NoValuesToFetch(whatHasHappened);
} }
void BaseStatement::throwInvalidColumnFetched(const char *whatHasHappened) const
{
throw InvalidColumnFetched(whatHasHappened);
}
void BaseStatement::throwBindingIndexIsOutOfRange(const char *whatHasHappened) const void BaseStatement::throwBindingIndexIsOutOfRange(const char *whatHasHappened) const
{ {
throw BindingIndexIsOutOfRange(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); throw BindingIndexIsOutOfRange(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
@@ -431,8 +391,9 @@ Database &BaseStatement::database() const
return m_database; return m_database;
} }
namespace {
template<typename StringType> 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)); const char *text = reinterpret_cast<const char*>(sqlite3_column_text(sqlStatment, column));
std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column)); std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column));
@@ -440,25 +401,43 @@ static StringType textForColumn(sqlite3_stmt *sqlStatment, int column)
return StringType(text, size); return StringType(text, size);
} }
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> 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); int dataType = sqlite3_column_type(sqlStatment, column);
switch (dataType) { switch (dataType) {
case SQLITE_INTEGER: case SQLITE_INTEGER:
case SQLITE_FLOAT: case SQLITE_FLOAT:
case SQLITE3_TEXT: return textForColumn<StringType>(sqlStatment, column); case SQLITE3_TEXT:
return textForColumn<StringType>(sqlStatment, column);
case SQLITE_BLOB: case SQLITE_BLOB:
case SQLITE_NULL: break; case SQLITE_NULL:
break;
} }
return StringType{"", 0}; return StringType{"", 0};
} }
} // namespace
int BaseStatement::fetchIntValue(int column) const int BaseStatement::fetchIntValue(int column) const
{ {
checkIfIsReadyToFetchValues();
checkColumnIsValid(column);
return sqlite3_column_int(m_compiledStatement.get(), column); return sqlite3_column_int(m_compiledStatement.get(), column);
} }
@@ -481,8 +460,6 @@ long BaseStatement::fetchValue<long>(int column) const
long long BaseStatement::fetchLongLongValue(int column) const long long BaseStatement::fetchLongLongValue(int column) const
{ {
checkIfIsReadyToFetchValues();
checkColumnIsValid(column);
return sqlite3_column_int64(m_compiledStatement.get(), column); return sqlite3_column_int64(m_compiledStatement.get(), column);
} }
@@ -494,11 +471,14 @@ long long BaseStatement::fetchValue<long long>(int column) const
double BaseStatement::fetchDoubleValue(int column) const double BaseStatement::fetchDoubleValue(int column) const
{ {
checkIfIsReadyToFetchValues();
checkColumnIsValid(column);
return sqlite3_column_double(m_compiledStatement.get(), column); return sqlite3_column_double(m_compiledStatement.get(), column);
} }
Utils::span<const byte> BaseStatement::fetchBlobValue(int column) const
{
return convertToBlobForColumn(m_compiledStatement.get(), column);
}
template<> template<>
double BaseStatement::fetchValue<double>(int column) const double BaseStatement::fetchValue<double>(int column) const
{ {
@@ -508,8 +488,6 @@ double BaseStatement::fetchValue<double>(int column) const
template<typename StringType> template<typename StringType>
StringType BaseStatement::fetchValue(int column) const StringType BaseStatement::fetchValue(int column) const
{ {
checkIfIsReadyToFetchValues();
checkColumnIsValid(column);
return convertToTextForColumn<StringType>(m_compiledStatement.get(), column); return convertToTextForColumn<StringType>(m_compiledStatement.get(), column);
} }
@@ -529,6 +507,8 @@ ValueView BaseStatement::fetchValueView(int column) const
{ {
int dataType = sqlite3_column_type(m_compiledStatement.get(), column); int dataType = sqlite3_column_type(m_compiledStatement.get(), column);
switch (dataType) { switch (dataType) {
case SQLITE_NULL:
return ValueView::create(NullValue{});
case SQLITE_INTEGER: case SQLITE_INTEGER:
return ValueView::create(fetchLongLongValue(column)); return ValueView::create(fetchLongLongValue(column));
case SQLITE_FLOAT: case SQLITE_FLOAT:
@@ -536,11 +516,10 @@ ValueView BaseStatement::fetchValueView(int column) const
case SQLITE3_TEXT: case SQLITE3_TEXT:
return ValueView::create(fetchValue<Utils::SmallStringView>(column)); return ValueView::create(fetchValue<Utils::SmallStringView>(column));
case SQLITE_BLOB: case SQLITE_BLOB:
case SQLITE_NULL:
break; break;
} }
return ValueView::create(0LL); return ValueView::create(NullValue{});
} }
} // namespace Sqlite } // namespace Sqlite

View File

@@ -33,6 +33,7 @@
#include <utils/smallstringvector.h> #include <utils/smallstringvector.h>
#include <utils/optional.h> #include <utils/optional.h>
#include <utils/span.h>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
@@ -69,16 +70,19 @@ public:
double fetchDoubleValue(int column) const; double fetchDoubleValue(int column) const;
Utils::SmallStringView fetchSmallStringViewValue(int column) const; Utils::SmallStringView fetchSmallStringViewValue(int column) const;
ValueView fetchValueView(int column) const; ValueView fetchValueView(int column) const;
Utils::span<const byte> fetchBlobValue(int column) const;
template<typename Type> template<typename Type>
Type fetchValue(int column) const; Type fetchValue(int column) const;
int columnCount() const; int columnCount() const;
Utils::SmallStringVector columnNames() const;
void bind(int index, NullValue);
void bind(int index, int fetchValue); void bind(int index, int fetchValue);
void bind(int index, long long fetchValue); void bind(int index, long long fetchValue);
void bind(int index, double fetchValue); void bind(int index, double fetchValue);
void bind(int index, void *pointer);
void bind(int index, Utils::SmallStringView fetchValue); void bind(int index, Utils::SmallStringView fetchValue);
void bind(int index, const Value &fetchValue); void bind(int index, const Value &fetchValue);
void bind(int index, Utils::span<const byte> bytes);
void bind(int index, uint value) { bind(index, static_cast<long long>(value)); } void bind(int index, uint value) { bind(index, static_cast<long long>(value)); }
@@ -87,25 +91,17 @@ public:
bind(index, static_cast<long long>(value)); bind(index, static_cast<long long>(value));
} }
template <typename Type>
void bind(Utils::SmallStringView name, Type fetchValue);
int bindingIndexForName(Utils::SmallStringView name) const;
void prepare(Utils::SmallStringView sqlStatement); void prepare(Utils::SmallStringView sqlStatement);
void waitForUnlockNotify() const; void waitForUnlockNotify() const;
sqlite3 *sqliteDatabaseHandle() const; sqlite3 *sqliteDatabaseHandle() const;
TextEncoding databaseTextEncoding();
[[noreturn]] void checkForStepError(int resultCode) const; [[noreturn]] void checkForStepError(int resultCode) const;
[[noreturn]] void checkForResetError(int resultCode) const; [[noreturn]] void checkForResetError(int resultCode) const;
[[noreturn]] void checkForPrepareError(int resultCode) const; [[noreturn]] void checkForPrepareError(int resultCode) const;
[[noreturn]] void checkForBindingError(int resultCode) const; [[noreturn]] void checkForBindingError(int resultCode) const;
void setIfIsReadyToFetchValues(int resultCode) const; void setIfIsReadyToFetchValues(int resultCode) const;
void checkIfIsReadyToFetchValues() const; void checkColumnCount(int columnCount) const;
void checkColumnsAreValid(const std::vector<int> &columns) const;
void checkColumnIsValid(int column) const;
void checkBindingName(int index) const; void checkBindingName(int index) const;
void setBindingParameterCount(); void setBindingParameterCount();
void setColumnCount(); void setColumnCount();
@@ -134,15 +130,8 @@ private:
Database &m_database; Database &m_database;
int m_bindingParameterCount; int m_bindingParameterCount;
int m_columnCount; int m_columnCount;
mutable bool m_isReadyToFetchValues;
}; };
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, int value);
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long value);
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long long value);
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, double value);
extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text);
template <> SQLITE_EXPORT int BaseStatement::fetchValue<int>(int column) const; template <> SQLITE_EXPORT int BaseStatement::fetchValue<int>(int column) const;
template <> SQLITE_EXPORT long BaseStatement::fetchValue<long>(int column) const; template <> SQLITE_EXPORT long BaseStatement::fetchValue<long>(int column) const;
template <> SQLITE_EXPORT long long BaseStatement::fetchValue<long long>(int column) const; template <> SQLITE_EXPORT long long BaseStatement::fetchValue<long long>(int column) const;
@@ -184,32 +173,21 @@ public:
resetter.reset(); resetter.reset();
} }
template<typename... ValueType>
void bindNameValues(const ValueType&... values)
{
bindValuesByName(values...);
}
template<typename... ValueType>
void writeNamed(const ValueType&... values)
{
Resetter resetter{*this};
bindValuesByName(values...);
BaseStatement::next();
resetter.reset();
}
template <typename ResultType, template <typename ResultType,
int ResultTypeCount = 1> int ResultTypeCount = 1>
std::vector<ResultType> values(std::size_t reserveSize) std::vector<ResultType> values(std::size_t reserveSize)
{ {
BaseStatement::checkColumnCount(ResultTypeCount);
Resetter resetter{*this}; Resetter resetter{*this};
std::vector<ResultType> resultValues; std::vector<ResultType> resultValues;
resultValues.reserve(reserveSize); resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
while (BaseStatement::next()) while (BaseStatement::next())
emplaceBackValues<ResultTypeCount>(resultValues); emplaceBackValues<ResultTypeCount>(resultValues);
setMaximumResultCount(resultValues.size());
resetter.reset(); resetter.reset();
return resultValues; return resultValues;
@@ -220,15 +198,19 @@ public:
typename... QueryTypes> typename... QueryTypes>
std::vector<ResultType> values(std::size_t reserveSize, const QueryTypes&... queryValues) std::vector<ResultType> values(std::size_t reserveSize, const QueryTypes&... queryValues)
{ {
BaseStatement::checkColumnCount(ResultTypeCount);
Resetter resetter{*this}; Resetter resetter{*this};
std::vector<ResultType> resultValues; std::vector<ResultType> resultValues;
resultValues.reserve(reserveSize); resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
bindValues(queryValues...); bindValues(queryValues...);
while (BaseStatement::next()) while (BaseStatement::next())
emplaceBackValues<ResultTypeCount>(resultValues); emplaceBackValues<ResultTypeCount>(resultValues);
setMaximumResultCount(resultValues.size());
resetter.reset(); resetter.reset();
return resultValues; return resultValues;
@@ -240,8 +222,10 @@ public:
std::vector<ResultType> values(std::size_t reserveSize, std::vector<ResultType> values(std::size_t reserveSize,
const std::vector<QueryElementType> &queryValues) const std::vector<QueryElementType> &queryValues)
{ {
BaseStatement::checkColumnCount(ResultTypeCount);
std::vector<ResultType> resultValues; std::vector<ResultType> resultValues;
resultValues.reserve(reserveSize); resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
for (const QueryElementType &queryValue : queryValues) { for (const QueryElementType &queryValue : queryValues) {
Resetter resetter{*this}; Resetter resetter{*this};
@@ -250,6 +234,8 @@ public:
while (BaseStatement::next()) while (BaseStatement::next())
emplaceBackValues<ResultTypeCount>(resultValues); emplaceBackValues<ResultTypeCount>(resultValues);
setMaximumResultCount(resultValues.size());
resetter.reset(); resetter.reset();
} }
@@ -262,9 +248,11 @@ public:
std::vector<ResultType> values(std::size_t reserveSize, std::vector<ResultType> values(std::size_t reserveSize,
const std::vector<std::tuple<QueryElementTypes...>> &queryTuples) const std::vector<std::tuple<QueryElementTypes...>> &queryTuples)
{ {
BaseStatement::checkColumnCount(ResultTypeCount);
using Container = std::vector<ResultType>; using Container = std::vector<ResultType>;
Container resultValues; Container resultValues;
resultValues.reserve(reserveSize); resultValues.reserve(std::max(reserveSize, m_maximumResultCount));
for (const auto &queryTuple : queryTuples) { for (const auto &queryTuple : queryTuples) {
Resetter resetter{*this}; Resetter resetter{*this};
@@ -273,6 +261,8 @@ public:
while (BaseStatement::next()) while (BaseStatement::next())
emplaceBackValues<ResultTypeCount>(resultValues); emplaceBackValues<ResultTypeCount>(resultValues);
setMaximumResultCount(resultValues.size());
resetter.reset(); resetter.reset();
} }
@@ -284,6 +274,8 @@ public:
typename... QueryTypes> typename... QueryTypes>
Utils::optional<ResultType> value(const QueryTypes&... queryValues) Utils::optional<ResultType> value(const QueryTypes&... queryValues)
{ {
BaseStatement::checkColumnCount(ResultTypeCount);
Resetter resetter{*this}; Resetter resetter{*this};
Utils::optional<ResultType> resultValue; Utils::optional<ResultType> resultValue;
@@ -302,6 +294,8 @@ public:
{ {
StatementImplementation statement(sqlStatement, database); StatementImplementation statement(sqlStatement, database);
statement.checkColumnCount(1);
statement.next(); statement.next();
return statement.template fetchValue<Type>(0); return statement.template fetchValue<Type>(0);
@@ -354,6 +348,7 @@ private:
operator long long() { return statement.fetchLongLongValue(column); } operator long long() { return statement.fetchLongLongValue(column); }
operator double() { return statement.fetchDoubleValue(column); } operator double() { return statement.fetchDoubleValue(column); }
operator Utils::SmallStringView() { return statement.fetchSmallStringViewValue(column); } operator Utils::SmallStringView() { return statement.fetchSmallStringViewValue(column); }
operator Utils::span<const Sqlite::byte>() { return statement.fetchBlobValue(column); }
operator ValueView() { return statement.fetchValueView(column); } operator ValueView() { return statement.fetchValueView(column); }
StatementImplementation &statement; StatementImplementation &statement;
@@ -401,19 +396,6 @@ private:
bindValuesByIndex(index + 1, values...); bindValuesByIndex(index + 1, values...);
} }
template<typename ValueType>
void bindValuesByName(Utils::SmallStringView name, const ValueType &value)
{
BaseStatement::bind(BaseStatement::bindingIndexForName(name), value);
}
template<typename ValueType, typename... ValueTypes>
void bindValuesByName(Utils::SmallStringView name, const ValueType &value, const ValueTypes&... values)
{
BaseStatement::bind(BaseStatement::bindingIndexForName(name), value);
bindValuesByName(values...);
}
template <typename TupleType, std::size_t... ColumnIndices> template <typename TupleType, std::size_t... ColumnIndices>
void bindTupleValuesElement(const TupleType &tuple, std::index_sequence<ColumnIndices...>) void bindTupleValuesElement(const TupleType &tuple, std::index_sequence<ColumnIndices...>)
{ {
@@ -427,6 +409,13 @@ private:
bindTupleValuesElement(element, ColumnIndices()); bindTupleValuesElement(element, ColumnIndices());
} }
void setMaximumResultCount(std::size_t count)
{
m_maximumResultCount = std::max(m_maximumResultCount, count);
}
public:
std::size_t m_maximumResultCount = 0;
}; };
} // namespace Sqlite } // namespace Sqlite

View File

@@ -25,72 +25,50 @@
#pragma once #pragma once
#include "sqliteglobal.h" #include "constraints.h"
#include <utils/smallstring.h>
#include <functional> #include <functional>
namespace Sqlite { namespace Sqlite {
class Column class Column
{ {
public: public:
Column() = default; Column() = default;
Column(Utils::SmallString &&name, Column(Utils::SmallStringView tableName,
ColumnType type = ColumnType::Numeric, Utils::SmallStringView name,
Contraint constraint = Contraint::NoConstraint) ColumnType type,
: m_name(std::move(name)), Constraints &&constraints = {})
m_type(type), : constraints(std::move(constraints))
m_constraint(constraint) , name(name)
, tableName(tableName)
, type(type)
{} {}
void clear() void clear()
{ {
m_name.clear(); name.clear();
m_type = ColumnType::Numeric; type = ColumnType::Numeric;
m_constraint = Contraint::NoConstraint; constraints = {};
}
void setName(Utils::SmallString &&newName)
{
m_name = newName;
}
const Utils::SmallString &name() const
{
return m_name;
}
void setType(ColumnType newType)
{
m_type = newType;
}
ColumnType type() const
{
return m_type;
}
void setContraint(Contraint constraint)
{
m_constraint = constraint;
}
Contraint constraint() const
{
return m_constraint;
} }
Utils::SmallString typeString() const Utils::SmallString typeString() const
{ {
switch (m_type) { switch (type) {
case ColumnType::None: return {}; case ColumnType::None:
case ColumnType::Numeric: return "NUMERIC"; return {};
case ColumnType::Integer: return "INTEGER"; case ColumnType::Numeric:
case ColumnType::Real: return "REAL"; return "NUMERIC";
case ColumnType::Text: return "TEXT"; case ColumnType::Integer:
return "INTEGER";
case ColumnType::Real:
return "REAL";
case ColumnType::Text:
return "TEXT";
case ColumnType::Blob:
return "BLOB";
} }
Q_UNREACHABLE(); Q_UNREACHABLE();
@@ -98,16 +76,16 @@ public:
friend bool operator==(const Column &first, const Column &second) friend bool operator==(const Column &first, const Column &second)
{ {
return first.m_name == second.m_name return first.name == second.name && first.type == second.type
&& first.m_type == second.m_type && first.constraints == second.constraints && first.tableName == second.tableName;
&& first.m_constraint == second.m_constraint;
} }
private: public:
Utils::SmallString m_name; Constraints constraints;
ColumnType m_type = ColumnType::Numeric; Utils::SmallString name;
Contraint m_constraint = Contraint::NoConstraint; Utils::SmallString tableName;
}; ColumnType type = ColumnType::Numeric;
}; // namespace Sqlite
using SqliteColumns = std::vector<Column>; using SqliteColumns = std::vector<Column>;
using SqliteColumnConstReference = std::reference_wrapper<const Column>; using SqliteColumnConstReference = std::reference_wrapper<const Column>;

View File

@@ -25,9 +25,10 @@
#include "sqlitedatabase.h" #include "sqlitedatabase.h"
#include "sqlitereadwritestatement.h"
#include "sqlitesessions.h"
#include "sqlitetable.h" #include "sqlitetable.h"
#include "sqlitetransaction.h" #include "sqlitetransaction.h"
#include "sqlitereadwritestatement.h"
#include <QFileInfo> #include <QFileInfo>
@@ -51,6 +52,7 @@ public:
ReadWriteStatement exclusiveBegin{"BEGIN EXCLUSIVE", database}; ReadWriteStatement exclusiveBegin{"BEGIN EXCLUSIVE", database};
ReadWriteStatement commitBegin{"COMMIT", database}; ReadWriteStatement commitBegin{"COMMIT", database};
ReadWriteStatement rollbackBegin{"ROLLBACK", database}; ReadWriteStatement rollbackBegin{"ROLLBACK", database};
Sessions sessions{database, "main", "databaseSessions"};
}; };
Database::Database() Database::Database()
@@ -60,21 +62,29 @@ Database::Database()
Database::Database(Utils::PathString &&databaseFilePath, JournalMode journalMode) Database::Database(Utils::PathString &&databaseFilePath, JournalMode journalMode)
: Database(std::move(databaseFilePath), 1000ms, journalMode) : Database(std::move(databaseFilePath), 1000ms, journalMode)
{ {}
}
Database::Database(Utils::PathString &&databaseFilePath, Database::Database(Utils::PathString &&databaseFilePath,
std::chrono::milliseconds busyTimeout, std::chrono::milliseconds busyTimeout,
JournalMode journalMode) JournalMode journalMode)
: m_databaseBackend(*this), : m_databaseBackend(*this)
m_busyTimeout(busyTimeout) , m_busyTimeout(busyTimeout)
{ {
setJournalMode(journalMode); setJournalMode(journalMode);
open(std::move(databaseFilePath)); open(std::move(databaseFilePath));
#ifndef QT_NO_DEBUG
execute("PRAGMA reverse_unordered_selects=1");
#endif
} }
Database::~Database() = default; Database::~Database() = default;
void Database::activateLogging()
{
DatabaseBackend::activateLogging();
}
void Database::open() void Database::open()
{ {
m_databaseBackend.open(m_databaseFilePath, m_openMode); m_databaseBackend.open(m_databaseFilePath, m_openMode);
@@ -131,6 +141,16 @@ void Database::setDatabaseFilePath(Utils::PathString &&databaseFilePath)
m_databaseFilePath = std::move(databaseFilePath); m_databaseFilePath = std::move(databaseFilePath);
} }
void Database::setAttachedTables(const Utils::SmallStringVector &tables)
{
m_statements->sessions.setAttachedTables(tables);
}
void Database::applyAndUpdateSessions()
{
m_statements->sessions.applyAndUpdateSessions();
}
const Utils::PathString &Database::databaseFilePath() const const Utils::PathString &Database::databaseFilePath() const
{ {
return m_databaseFilePath; return m_databaseFilePath;
@@ -210,6 +230,22 @@ void Database::rollback()
m_statements->rollbackBegin.execute(); m_statements->rollbackBegin.execute();
} }
void Database::immediateSessionBegin()
{
m_statements->immediateBegin.execute();
m_statements->sessions.create();
}
void Database::sessionCommit()
{
m_statements->sessions.commit();
m_statements->commitBegin.execute();
}
void Database::sessionRollback()
{
m_statements->sessions.rollback();
m_statements->rollbackBegin.execute();
}
void Database::lock() void Database::lock()
{ {
m_databaseMutex.lock(); m_databaseMutex.lock();

View File

@@ -66,6 +66,8 @@ public:
Database(const Database &) = delete; Database(const Database &) = delete;
Database &operator=(const Database &) = delete; Database &operator=(const Database &) = delete;
static void activateLogging();
void open(); void open();
void open(Utils::PathString &&databaseFilePath); void open(Utils::PathString &&databaseFilePath);
void close(); void close();
@@ -108,7 +110,21 @@ public:
int totalChangesCount() { return m_databaseBackend.totalChangesCount(); } int totalChangesCount() { return m_databaseBackend.totalChangesCount(); }
void walCheckpointFull() override { m_databaseBackend.walCheckpointFull(); } void walCheckpointFull() override
{
std::lock_guard<std::mutex> lock{m_databaseMutex};
m_databaseBackend.walCheckpointFull();
}
void setUpdateHook(DatabaseBackend::UpdateCallback &callback)
{
m_databaseBackend.setUpdateHook(callback);
}
void resetUpdateHook() { m_databaseBackend.resetUpdateHook(); }
void setAttachedTables(const Utils::SmallStringVector &tables);
void applyAndUpdateSessions();
private: private:
void deferredBegin() override; void deferredBegin() override;
@@ -118,6 +134,9 @@ private:
void rollback() override; void rollback() override;
void lock() override; void lock() override;
void unlock() override; void unlock() override;
void immediateSessionBegin() override;
void sessionCommit() override;
void sessionRollback() override;
void initializeTables(); void initializeTables();
void registerTransactionStatements(); void registerTransactionStatements();

View File

@@ -37,12 +37,15 @@
#include "sqlite3.h" #include "sqlite3.h"
extern "C" {
int sqlite3_carray_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi);
}
namespace Sqlite { namespace Sqlite {
DatabaseBackend::DatabaseBackend(Database &database) DatabaseBackend::DatabaseBackend(Database &database)
: m_database(database), : m_database(database)
m_databaseHandle(nullptr), , m_databaseHandle(nullptr)
m_cachedTextEncoding(Utf8)
{ {
} }
@@ -65,14 +68,16 @@ void DatabaseBackend::activateMultiThreading()
static void sqliteLog(void*,int errorCode,const char *errorMessage) static void sqliteLog(void*,int errorCode,const char *errorMessage)
{ {
qWarning() << sqlite3_errstr(errorCode) << errorMessage; std::cout << "Sqlite " << sqlite3_errstr(errorCode) << ": " << errorMessage << std::endl;
} }
void DatabaseBackend::activateLogging() void DatabaseBackend::activateLogging()
{ {
if (qEnvironmentVariableIsSet("QTC_SQLITE_LOGGING")) {
int resultCode = sqlite3_config(SQLITE_CONFIG_LOG, sqliteLog, nullptr); int resultCode = sqlite3_config(SQLITE_CONFIG_LOG, sqliteLog, nullptr);
checkIfLoogingIsActivated(resultCode); checkIfLoogingIsActivated(resultCode);
} }
}
void DatabaseBackend::initializeSqliteLibrary() void DatabaseBackend::initializeSqliteLibrary()
{ {
@@ -103,7 +108,9 @@ void DatabaseBackend::open(Utils::SmallStringView databaseFilePath, OpenMode mod
checkDatabaseCouldBeOpened(resultCode); checkDatabaseCouldBeOpened(resultCode);
cacheTextEncoding(); resultCode = sqlite3_carray_init(m_databaseHandle, nullptr, nullptr);
checkCarrayCannotBeIntialized(resultCode);
} }
sqlite3 *DatabaseBackend::sqliteDatabaseHandle() const sqlite3 *DatabaseBackend::sqliteDatabaseHandle() const
@@ -135,24 +142,6 @@ JournalMode DatabaseBackend::journalMode()
return pragmaToJournalMode(pragmaValue("journal_mode")); return pragmaToJournalMode(pragmaValue("journal_mode"));
} }
void DatabaseBackend::setTextEncoding(TextEncoding textEncoding)
{
setPragmaValue("encoding", textEncodingToPragma(textEncoding));
cacheTextEncoding();
}
TextEncoding DatabaseBackend::textEncoding()
{
return m_cachedTextEncoding;
}
Utils::SmallStringVector DatabaseBackend::columnNames(Utils::SmallStringView tableName)
{
ReadWriteStatement statement("SELECT * FROM " + tableName, m_database);
return statement.columnNames();
}
int DatabaseBackend::changesCount() const int DatabaseBackend::changesCount() const
{ {
return sqlite3_changes(sqliteDatabaseHandle()); return sqlite3_changes(sqliteDatabaseHandle());
@@ -232,11 +221,6 @@ int DatabaseBackend::busyHandlerCallback(void *, int counter)
return true; return true;
} }
void DatabaseBackend::cacheTextEncoding()
{
m_cachedTextEncoding = pragmaToTextEncoding(pragmaValue("encoding"));
}
void DatabaseBackend::checkForOpenDatabaseWhichCanBeClosed() void DatabaseBackend::checkForOpenDatabaseWhichCanBeClosed()
{ {
if (m_databaseHandle == nullptr) if (m_databaseHandle == nullptr)
@@ -272,10 +256,19 @@ void DatabaseBackend::checkDatabaseCouldBeOpened(int resultCode)
return; return;
default: default:
closeWithoutException(); closeWithoutException();
throw Exception("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened:", sqlite3_errmsg(sqliteDatabaseHandle())); throw Exception(
"SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened:",
sqlite3_errmsg(sqliteDatabaseHandle()));
} }
} }
void DatabaseBackend::checkCarrayCannotBeIntialized(int resultCode)
{
if (resultCode != SQLITE_OK)
throwDatabaseIsNotOpen(
"SqliteDatabaseBackend: database cannot be opened because carray failed!");
}
void DatabaseBackend::checkPragmaValue(Utils::SmallStringView databaseValue, void DatabaseBackend::checkPragmaValue(Utils::SmallStringView databaseValue,
Utils::SmallStringView expectedValue) Utils::SmallStringView expectedValue)
{ {
@@ -292,31 +285,35 @@ void DatabaseBackend::checkDatabaseHandleIsNotNull() const
void DatabaseBackend::checkIfMultithreadingIsActivated(int resultCode) void DatabaseBackend::checkIfMultithreadingIsActivated(int resultCode)
{ {
if (resultCode != SQLITE_OK) if (resultCode != SQLITE_OK)
throwException("SqliteDatabaseBackend::activateMultiThreading: multithreading can't be activated!"); throwExceptionStatic(
"SqliteDatabaseBackend::activateMultiThreading: multithreading can't be activated!");
} }
void DatabaseBackend::checkIfLoogingIsActivated(int resultCode) void DatabaseBackend::checkIfLoogingIsActivated(int resultCode)
{ {
if (resultCode != SQLITE_OK) if (resultCode != SQLITE_OK)
throwException("SqliteDatabaseBackend::activateLogging: logging can't be activated!"); throwExceptionStatic("SqliteDatabaseBackend::activateLogging: logging can't be activated!");
} }
void DatabaseBackend::checkMmapSizeIsSet(int resultCode) void DatabaseBackend::checkMmapSizeIsSet(int resultCode)
{ {
if (resultCode != SQLITE_OK) if (resultCode != SQLITE_OK)
throwException("SqliteDatabaseBackend::checkMmapSizeIsSet: mmap size can't be changed!"); throwExceptionStatic(
"SqliteDatabaseBackend::checkMmapSizeIsSet: mmap size can't be changed!");
} }
void DatabaseBackend::checkInitializeSqliteLibraryWasSuccesful(int resultCode) void DatabaseBackend::checkInitializeSqliteLibraryWasSuccesful(int resultCode)
{ {
if (resultCode != SQLITE_OK) if (resultCode != SQLITE_OK)
throwException("SqliteDatabaseBackend::initializeSqliteLibrary: SqliteLibrary cannot initialized!"); throwExceptionStatic(
"SqliteDatabaseBackend::initializeSqliteLibrary: SqliteLibrary cannot initialized!");
} }
void DatabaseBackend::checkShutdownSqliteLibraryWasSuccesful(int resultCode) void DatabaseBackend::checkShutdownSqliteLibraryWasSuccesful(int resultCode)
{ {
if (resultCode != SQLITE_OK) if (resultCode != SQLITE_OK)
throwException("SqliteDatabaseBackend::shutdownSqliteLibrary: SqliteLibrary cannot be shutdowned!"); throwExceptionStatic(
"SqliteDatabaseBackend::shutdownSqliteLibrary: SqliteLibrary cannot be shutdowned!");
} }
void DatabaseBackend::checkIfLogCouldBeCheckpointed(int resultCode) void DatabaseBackend::checkIfLogCouldBeCheckpointed(int resultCode)
@@ -344,13 +341,11 @@ int indexOfPragma(Utils::SmallStringView pragma, const Utils::SmallStringView (&
} }
} }
constexpr const Utils::SmallStringView journalModeStrings[] = { const Utils::SmallStringView journalModeStrings[] = {"delete",
"delete",
"truncate", "truncate",
"persist", "persist",
"memory", "memory",
"wal" "wal"};
};
Utils::SmallStringView DatabaseBackend::journalModeToPragma(JournalMode journalMode) Utils::SmallStringView DatabaseBackend::journalModeToPragma(JournalMode journalMode)
{ {
@@ -367,27 +362,6 @@ JournalMode DatabaseBackend::pragmaToJournalMode(Utils::SmallStringView pragma)
return static_cast<JournalMode>(index); return static_cast<JournalMode>(index);
} }
constexpr const Utils::SmallStringView textEncodingStrings[] = {
"UTF-8",
"UTF-16le",
"UTF-16be"
};
Utils::SmallStringView DatabaseBackend::textEncodingToPragma(TextEncoding textEncoding)
{
return textEncodingStrings[textEncoding];
}
TextEncoding DatabaseBackend::pragmaToTextEncoding(Utils::SmallStringView pragma)
{
int index = indexOfPragma(pragma, textEncodingStrings);
if (index < 0)
throwExceptionStatic("SqliteDatabaseBackend::pragmaToTextEncoding: pragma can't be transformed in a text encoding enumeration!");
return static_cast<TextEncoding>(index);
}
int DatabaseBackend::openMode(OpenMode mode) int DatabaseBackend::openMode(OpenMode mode)
{ {
int sqliteMode = SQLITE_OPEN_CREATE; int sqliteMode = SQLITE_OPEN_CREATE;
@@ -426,6 +400,29 @@ void DatabaseBackend::walCheckpointFull()
} }
} }
namespace {
void updateCallback(
void *callback, int type, char const *database, char const *table, sqlite3_int64 row)
{
auto &function = *reinterpret_cast<DatabaseBackend::UpdateCallback *>(callback);
function(static_cast<ChangeType>(type), database, table, row);
}
} // namespace
void DatabaseBackend::setUpdateHook(UpdateCallback &callback)
{
if (callback)
sqlite3_update_hook(m_databaseHandle, updateCallback, &callback);
else
sqlite3_update_hook(m_databaseHandle, nullptr, nullptr);
}
void DatabaseBackend::resetUpdateHook()
{
sqlite3_update_hook(m_databaseHandle, nullptr, nullptr);
}
void DatabaseBackend::throwExceptionStatic(const char *whatHasHappens) void DatabaseBackend::throwExceptionStatic(const char *whatHasHappens)
{ {
throw Exception(whatHasHappens); throw Exception(whatHasHappens);

View File

@@ -40,6 +40,9 @@ class Database;
class SQLITE_EXPORT DatabaseBackend class SQLITE_EXPORT DatabaseBackend
{ {
public: public:
using UpdateCallback
= std::function<void(ChangeType type, char const *, char const *, long long)>;
DatabaseBackend(Database &database); DatabaseBackend(Database &database);
~DatabaseBackend(); ~DatabaseBackend();
@@ -49,11 +52,11 @@ public:
DatabaseBackend(DatabaseBackend &&) = delete; DatabaseBackend(DatabaseBackend &&) = delete;
DatabaseBackend &operator=(DatabaseBackend &&) = delete; DatabaseBackend &operator=(DatabaseBackend &&) = delete;
void setMmapSize(qint64 defaultSize, qint64 maximumSize); static void setMmapSize(qint64 defaultSize, qint64 maximumSize);
void activateMultiThreading(); static void activateMultiThreading();
void activateLogging(); static void activateLogging();
void initializeSqliteLibrary(); static void initializeSqliteLibrary();
void shutdownSqliteLibrary(); static void shutdownSqliteLibrary();
void checkpointFullWalLog(); void checkpointFullWalLog();
void open(Utils::SmallStringView databaseFilePath, OpenMode openMode); void open(Utils::SmallStringView databaseFilePath, OpenMode openMode);
@@ -65,9 +68,6 @@ public:
void setJournalMode(JournalMode journalMode); void setJournalMode(JournalMode journalMode);
JournalMode journalMode(); JournalMode journalMode();
void setTextEncoding(TextEncoding textEncoding);
TextEncoding textEncoding();
Utils::SmallStringVector columnNames(Utils::SmallStringView tableName); Utils::SmallStringVector columnNames(Utils::SmallStringView tableName);
int changesCount() const; int changesCount() const;
@@ -87,6 +87,9 @@ public:
void walCheckpointFull(); void walCheckpointFull();
void setUpdateHook(UpdateCallback &callback);
void resetUpdateHook();
protected: protected:
bool databaseIsOpen() const; bool databaseIsOpen() const;
@@ -97,27 +100,23 @@ protected:
void registerRankingFunction(); void registerRankingFunction();
static int busyHandlerCallback(void*, int counter); static int busyHandlerCallback(void*, int counter);
void cacheTextEncoding();
void checkForOpenDatabaseWhichCanBeClosed(); void checkForOpenDatabaseWhichCanBeClosed();
void checkDatabaseClosing(int resultCode); void checkDatabaseClosing(int resultCode);
void checkCanOpenDatabase(Utils::SmallStringView databaseFilePath); void checkCanOpenDatabase(Utils::SmallStringView databaseFilePath);
void checkDatabaseCouldBeOpened(int resultCode); void checkDatabaseCouldBeOpened(int resultCode);
void checkCarrayCannotBeIntialized(int resultCode);
void checkPragmaValue(Utils::SmallStringView databaseValue, Utils::SmallStringView expectedValue); void checkPragmaValue(Utils::SmallStringView databaseValue, Utils::SmallStringView expectedValue);
void checkDatabaseHandleIsNotNull() const; void checkDatabaseHandleIsNotNull() const;
void checkIfMultithreadingIsActivated(int resultCode); static void checkIfMultithreadingIsActivated(int resultCode);
void checkIfLoogingIsActivated(int resultCode); static void checkIfLoogingIsActivated(int resultCode);
void checkMmapSizeIsSet(int resultCode); static void checkMmapSizeIsSet(int resultCode);
void checkInitializeSqliteLibraryWasSuccesful(int resultCode); static void checkInitializeSqliteLibraryWasSuccesful(int resultCode);
void checkShutdownSqliteLibraryWasSuccesful(int resultCode); static void checkShutdownSqliteLibraryWasSuccesful(int resultCode);
void checkIfLogCouldBeCheckpointed(int resultCode); void checkIfLogCouldBeCheckpointed(int resultCode);
void checkIfBusyTimeoutWasSet(int resultCode); void checkIfBusyTimeoutWasSet(int resultCode);
static Utils::SmallStringView journalModeToPragma(JournalMode journalMode); static Utils::SmallStringView journalModeToPragma(JournalMode journalMode);
static JournalMode pragmaToJournalMode(Utils::SmallStringView pragma); static JournalMode pragmaToJournalMode(Utils::SmallStringView pragma);
Utils::SmallStringView textEncodingToPragma(TextEncoding textEncoding);
static TextEncoding pragmaToTextEncoding(Utils::SmallStringView pragma);
Q_NORETURN static void throwExceptionStatic(const char *whatHasHappens); Q_NORETURN static void throwExceptionStatic(const char *whatHasHappens);
[[noreturn]] void throwException(const char *whatHasHappens) const; [[noreturn]] void throwException(const char *whatHasHappens) const;
@@ -127,8 +126,6 @@ protected:
private: private:
Database &m_database; Database &m_database;
sqlite3 *m_databaseHandle; sqlite3 *m_databaseHandle;
TextEncoding m_cachedTextEncoding;
}; };
} // namespace Sqlite } // namespace Sqlite

View File

@@ -25,11 +25,25 @@
#pragma once #pragma once
#include <utils/smallstringvector.h>
#include "sqliteglobal.h"
#include <functional>
namespace Sqlite { namespace Sqlite {
class DatabaseInterface class DatabaseInterface
{ {
public: public:
using UpdateCallback
= std::function<void(ChangeType type, char const *, char const *, long long)>;
virtual void walCheckpointFull() = 0; virtual void walCheckpointFull() = 0;
virtual void execute(Utils::SmallStringView sqlStatement) = 0;
virtual void setUpdateHook(UpdateCallback &callback) = 0;
virtual void resetUpdateHook() = 0;
virtual void applyAndUpdateSessions() = 0;
virtual void setAttachedTables(const Utils::SmallStringVector &tables) = 0;
protected: protected:
~DatabaseInterface() = default; ~DatabaseInterface() = default;

View File

@@ -29,17 +29,21 @@
#include <utils/smallstring.h> #include <utils/smallstring.h>
#include <exception>
#include <iostream>
namespace Sqlite { namespace Sqlite {
class SQLITE_EXPORT Exception class SQLITE_EXPORT Exception : public std::exception
{ {
public: public:
Exception(const char *whatErrorHasHappen, Exception(const char *whatErrorHasHappen,
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
: m_whatErrorHasHappen(whatErrorHasHappen), : m_whatErrorHasHappen(whatErrorHasHappen)
m_sqliteErrorMessage(std::move(sqliteErrorMessage)) , m_sqliteErrorMessage(std::move(sqliteErrorMessage))
{ {}
}
const char *what() const noexcept override { return m_whatErrorHasHappen; }
void printWarning() const; void printWarning() const;
@@ -115,13 +119,12 @@ public:
} }
}; };
class InvalidColumnFetched : public Exception class ColumnCountDoesNotMatch : public Exception
{ {
public: public:
InvalidColumnFetched(const char *whatErrorHasHappen) ColumnCountDoesNotMatch(const char *whatErrorHasHappen)
: Exception(whatErrorHasHappen) : Exception(whatErrorHasHappen)
{ {}
}
}; };
class BindingIndexIsOutOfRange : public Exception class BindingIndexIsOutOfRange : public Exception
@@ -272,4 +275,28 @@ public:
{} {}
}; };
class ForeignKeyColumnIsNotUnique : public Exception
{
public:
ForeignKeyColumnIsNotUnique(const char *whatErrorHasHappen)
: Exception(whatErrorHasHappen)
{}
};
class CannotApplyChangeSet : public Exception
{
public:
CannotApplyChangeSet(const char *whatErrorHasHappen)
: Exception(whatErrorHasHappen)
{}
};
class ChangeSetIsMisused : public Exception
{
public:
ChangeSetIsMisused(const char *whatErrorHasHappen)
: Exception(whatErrorHasHappen)
{}
};
} // namespace Sqlite } // namespace Sqlite

View File

@@ -39,26 +39,15 @@
namespace Sqlite { namespace Sqlite {
enum class ColumnType : char enum class ColumnType : char { Numeric, Integer, Real, Text, Blob, None };
{
Numeric,
Integer,
Real,
Text,
None
};
enum class Contraint : char enum class ConstraintType : char { NoConstraint, PrimaryKey, Unique, ForeignKey };
{
NoConstraint,
PrimaryKey,
Unique
};
enum class ColumnConstraint : char enum class ForeignKeyAction : char { NoAction, Restrict, SetNull, SetDefault, Cascade };
{
PrimaryKey enum class Enforment : char { Immediate, Deferred };
};
enum class ColumnConstraint : char { PrimaryKey };
enum class JournalMode : char enum class JournalMode : char
{ {
@@ -75,17 +64,8 @@ enum class OpenMode : char
ReadWrite ReadWrite
}; };
enum TextEncoding : char enum class ChangeType : int { Delete = 9, Insert = 18, Update = 23 };
{
Utf8,
Utf16le,
Utf16be,
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
Utf16 = Utf16le
#else
Utf16 = Utf16be
#endif
}; enum class byte : unsigned char {};
} // namespace Sqlite } // namespace Sqlite

View File

@@ -41,7 +41,6 @@ public:
using StatementImplementation::values; using StatementImplementation::values;
using StatementImplementation::toValue; using StatementImplementation::toValue;
using StatementImplementation::write; using StatementImplementation::write;
using StatementImplementation::writeNamed;
}; };
} // namespace Sqlite } // namespace Sqlite

View 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

View 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

View 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

View 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

View File

@@ -44,10 +44,7 @@ public:
m_sqliteIndices.reserve(reserve); m_sqliteIndices.reserve(reserve);
} }
void setName(Utils::SmallString &&name) void setName(Utils::SmallStringView name) { m_tableName = name; }
{
m_tableName = std::move(name);
}
Utils::SmallStringView name() const Utils::SmallStringView name() const
{ {
@@ -74,15 +71,69 @@ public:
m_useTemporaryTable = useTemporaryTable; m_useTemporaryTable = useTemporaryTable;
} }
Column &addColumn(Utils::SmallString &&name, Column &addColumn(Utils::SmallStringView name,
ColumnType type = ColumnType::Numeric, ColumnType type = ColumnType::Numeric,
Contraint constraint = Contraint::NoConstraint) Constraints &&constraints = {})
{ {
m_sqliteColumns.emplace_back(std::move(name), type, constraint); m_sqliteColumns.emplace_back(m_tableName, name, type, std::move(constraints));
return m_sqliteColumns.back(); return m_sqliteColumns.back();
} }
Column &addForeignKeyColumn(Utils::SmallStringView name,
const Table &referencedTable,
ForeignKeyAction foreignKeyupdateAction = {},
ForeignKeyAction foreignKeyDeleteAction = {},
Enforment foreignKeyEnforcement = {},
Constraints &&constraints = {},
ColumnType type = ColumnType::Integer)
{
constraints.emplace_back(ForeignKey{referencedTable.name(),
"",
foreignKeyupdateAction,
foreignKeyDeleteAction,
foreignKeyEnforcement});
m_sqliteColumns.emplace_back(m_tableName, name, type, std::move(constraints));
return m_sqliteColumns.back();
}
Column &addForeignKeyColumn(Utils::SmallStringView name,
const Column &referencedColumn,
ForeignKeyAction foreignKeyupdateAction = {},
ForeignKeyAction foreignKeyDeleteAction = {},
Enforment foreignKeyEnforcement = {},
Constraints &&constraints = {})
{
if (!constainsUniqueIndex(referencedColumn.constraints))
throw ForeignKeyColumnIsNotUnique("Foreign column key must be unique!");
constraints.emplace_back(ForeignKey{referencedColumn.tableName,
referencedColumn.name,
foreignKeyupdateAction,
foreignKeyDeleteAction,
foreignKeyEnforcement});
m_sqliteColumns.emplace_back(m_tableName,
name,
referencedColumn.type,
std::move(constraints));
return m_sqliteColumns.back();
}
void addPrimaryKeyContraint(const SqliteColumnConstReferences &columns)
{
Utils::SmallStringVector columnNames;
columnNames.reserve(columns.size());
for (const auto &column : columns)
columnNames.emplace_back(column.get().name);
m_tableConstraints.emplace_back(TablePrimaryKey{std::move(columnNames)});
}
Index &addIndex(const SqliteColumnConstReferences &columns) Index &addIndex(const SqliteColumnConstReferences &columns)
{ {
m_sqliteIndices.emplace_back(m_tableName.clone(), sqliteColumnNames(columns)); m_sqliteIndices.emplace_back(m_tableName.clone(), sqliteColumnNames(columns));
@@ -119,6 +170,7 @@ public:
builder.setUseIfNotExists(m_useIfNotExists); builder.setUseIfNotExists(m_useIfNotExists);
builder.setUseTemporaryTable(m_useTemporaryTable); builder.setUseTemporaryTable(m_useTemporaryTable);
builder.setColumns(m_sqliteColumns); builder.setColumns(m_sqliteColumns);
builder.setConstraints(m_tableConstraints);
database.execute(builder.sqlStatement()); database.execute(builder.sqlStatement());
@@ -142,13 +194,23 @@ public:
&& first.m_sqliteColumns == second.m_sqliteColumns; && first.m_sqliteColumns == second.m_sqliteColumns;
} }
static bool constainsUniqueIndex(const Constraints &constraints)
{
return std::find_if(constraints.begin(),
constraints.end(),
[](const Constraint &constraint) {
return Utils::holds_alternative<Unique>(constraint);
})
!= constraints.end();
}
private: private:
Utils::SmallStringVector sqliteColumnNames(const SqliteColumnConstReferences &columns) Utils::SmallStringVector sqliteColumnNames(const SqliteColumnConstReferences &columns)
{ {
Utils::SmallStringVector columnNames; Utils::SmallStringVector columnNames;
for (const Column &column : columns) for (const Column &column : columns)
columnNames.push_back(column.name()); columnNames.push_back(column.name);
return columnNames; return columnNames;
} }
@@ -157,6 +219,7 @@ private:
Utils::SmallString m_tableName; Utils::SmallString m_tableName;
SqliteColumns m_sqliteColumns; SqliteColumns m_sqliteColumns;
SqliteIndices m_sqliteIndices; SqliteIndices m_sqliteIndices;
TableConstraints m_tableConstraints;
bool m_withoutRowId = false; bool m_withoutRowId = false;
bool m_useIfNotExists = false; bool m_useIfNotExists = false;
bool m_useTemporaryTable = false; bool m_useTemporaryTable = false;

View File

@@ -27,6 +27,8 @@
#include "sqliteglobal.h" #include "sqliteglobal.h"
#include <utils/smallstringview.h>
#include <exception> #include <exception>
#include <mutex> #include <mutex>
@@ -49,6 +51,9 @@ public:
virtual void rollback() = 0; virtual void rollback() = 0;
virtual void lock() = 0; virtual void lock() = 0;
virtual void unlock() = 0; virtual void unlock() = 0;
virtual void immediateSessionBegin() = 0;
virtual void sessionCommit() = 0;
virtual void sessionRollback() = 0;
protected: protected:
~TransactionInterface() = default; ~TransactionInterface() = default;
@@ -82,6 +87,42 @@ protected:
bool m_rollback = false; bool m_rollback = false;
}; };
class AbstractThrowingSessionTransaction
{
public:
AbstractThrowingSessionTransaction(const AbstractTransaction &) = delete;
AbstractThrowingSessionTransaction &operator=(const AbstractTransaction &) = delete;
void commit()
{
m_interface.sessionCommit();
m_isAlreadyCommited = true;
m_locker.unlock();
}
~AbstractThrowingSessionTransaction() noexcept(false)
{
try {
if (m_rollback)
m_interface.sessionRollback();
} catch (...) {
if (!std::uncaught_exception())
throw;
}
}
protected:
AbstractThrowingSessionTransaction(TransactionInterface &interface)
: m_interface(interface)
{}
protected:
TransactionInterface &m_interface;
std::unique_lock<TransactionInterface> m_locker{m_interface};
bool m_isAlreadyCommited = false;
bool m_rollback = false;
};
class AbstractThrowingTransaction : public AbstractTransaction class AbstractThrowingTransaction : public AbstractTransaction
{ {
public: public:
@@ -181,6 +222,23 @@ public:
}; };
using ExclusiveTransaction = BasicExclusiveTransaction<AbstractThrowingTransaction>; using ExclusiveTransaction = BasicExclusiveTransaction<AbstractThrowingTransaction>;
using ExclusiveNonThrowingDestructorTransaction = BasicExclusiveTransaction<AbstractNonThrowingDestructorTransaction>; using ExclusiveNonThrowingDestructorTransaction
= BasicExclusiveTransaction<AbstractNonThrowingDestructorTransaction>;
class ImmediateSessionTransaction final : public AbstractThrowingSessionTransaction
{
public:
ImmediateSessionTransaction(TransactionInterface &interface)
: AbstractThrowingSessionTransaction(interface)
{
interface.immediateSessionBegin();
}
~ImmediateSessionTransaction()
{
AbstractThrowingSessionTransaction::m_rollback
= !AbstractThrowingSessionTransaction::m_isAlreadyCommited;
}
};
} // namespace Sqlite } // namespace Sqlite

View File

@@ -30,17 +30,29 @@
#include <QVariant> #include <QVariant>
#include <cstddef>
#pragma once #pragma once
namespace Sqlite { namespace Sqlite {
enum class ValueType : unsigned char { Integer, Float, String }; enum class ValueType : unsigned char { Null, Integer, Float, String };
class NullValue
{
friend bool operator==(NullValue, NullValue) { return false; }
};
template<typename StringType> template<typename StringType>
class ValueBase class ValueBase
{ {
public: public:
using VariantType = Utils::variant<long long, double, StringType>; using VariantType = Utils::variant<NullValue, long long, double, StringType>;
ValueBase() = default;
explicit ValueBase(NullValue) {}
explicit ValueBase(VariantType &&value) explicit ValueBase(VariantType &&value)
: value(value) : value(value)
@@ -70,6 +82,8 @@ public:
{} {}
bool isNull() const { return value.index() == 0; }
long long toInteger() const { return Utils::get<int(ValueType::Integer)>(value); } long long toInteger() const { return Utils::get<int(ValueType::Integer)>(value); }
double toFloat() const { return Utils::get<int(ValueType::Float)>(value); } double toFloat() const { return Utils::get<int(ValueType::Float)>(value); }
@@ -93,6 +107,8 @@ public:
return {}; return {};
} }
friend bool operator==(const ValueBase &first, std::nullptr_t) { return first.isNull(); }
friend bool operator==(const ValueBase &first, long long second) friend bool operator==(const ValueBase &first, long long second)
{ {
auto maybeInteger = Utils::get_if<int(ValueType::Integer)>(&first.value); auto maybeInteger = Utils::get_if<int(ValueType::Integer)>(&first.value);
@@ -171,10 +187,12 @@ public:
{ {
switch (value.index()) { switch (value.index()) {
case 0: case 0:
return ValueType::Integer; return ValueType::Null;
case 1: case 1:
return ValueType::Float; return ValueType::Integer;
case 2: case 2:
return ValueType::Float;
case 3:
return ValueType::String; return ValueType::String;
} }
@@ -206,6 +224,10 @@ class Value : public ValueBase<Utils::SmallString>
public: public:
using Base::Base; using Base::Base;
Value() = default;
explicit Value(NullValue) {}
explicit Value(ValueView view) explicit Value(ValueView view)
: ValueBase(convert(view)) : ValueBase(convert(view))
{} {}
@@ -226,6 +248,10 @@ public:
: ValueBase(VariantType{Utils::SmallString(value)}) : ValueBase(VariantType{Utils::SmallString(value)})
{} {}
explicit Value(const std::string &value)
: ValueBase(VariantType{Utils::SmallString(value)})
{}
friend bool operator!=(const Value &first, const Value &second) friend bool operator!=(const Value &first, const Value &second)
{ {
return !(first.value == second.value); return !(first.value == second.value);
@@ -265,6 +291,9 @@ public:
private: private:
static Base::VariantType convert(const QVariant &value) static Base::VariantType convert(const QVariant &value)
{ {
if (value.isNull())
return VariantType{NullValue{}};
switch (value.type()) { switch (value.type()) {
case QVariant::Int: case QVariant::Int:
return VariantType{static_cast<long long>(value.toInt())}; return VariantType{static_cast<long long>(value.toInt())};
@@ -284,6 +313,8 @@ private:
static Base::VariantType convert(ValueView view) static Base::VariantType convert(ValueView view)
{ {
switch (view.type()) { switch (view.type()) {
case ValueType::Null:
return VariantType(NullValue{});
case ValueType::Integer: case ValueType::Integer:
return VariantType{view.toInteger()}; return VariantType{view.toInteger()};
case ValueType::Float: case ValueType::Float:

View File

@@ -37,7 +37,6 @@ public:
using StatementImplementation::execute; using StatementImplementation::execute;
using StatementImplementation::database; using StatementImplementation::database;
using StatementImplementation::write; using StatementImplementation::write;
using StatementImplementation::writeNamed;
protected: protected:
void checkIsWritableStatement(); void checkIsWritableStatement();

View 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

View File

@@ -6,6 +6,7 @@ add_qtc_library(Utils
SOURCES SOURCES
../3rdparty/optional/optional.hpp ../3rdparty/optional/optional.hpp
../3rdparty/variant/variant.hpp ../3rdparty/variant/variant.hpp
../3rdparty/span/span.hpp
QtConcurrentTools QtConcurrentTools
algorithm.h algorithm.h
ansiescapecodehandler.cpp ansiescapecodehandler.h ansiescapecodehandler.cpp ansiescapecodehandler.h
@@ -137,6 +138,7 @@ add_qtc_library(Utils
smallstringmemory.h smallstringmemory.h
smallstringvector.h smallstringvector.h
smallstringview.h smallstringview.h
span.h
statuslabel.cpp statuslabel.h statuslabel.cpp statuslabel.h
stringutils.cpp stringutils.h stringutils.cpp stringutils.h
styledbar.cpp styledbar.h styledbar.cpp styledbar.h

View File

@@ -90,39 +90,35 @@ public:
constexpr constexpr
BasicSmallString(const char(&string)[ArraySize]) BasicSmallString(const char(&string)[ArraySize])
: m_data(string) : m_data(string)
{ {}
}
BasicSmallString(const char *string, size_type size, size_type capacity) BasicSmallString(const char *string, size_type size, size_type capacity)
{ {
if (Q_LIKELY(capacity <= shortStringCapacity())) { if (Q_LIKELY(capacity <= shortStringCapacity())) {
std::memcpy(m_data.shortString.string, string, size); std::char_traits<char>::copy(m_data.shortString.string, string, size);
m_data.shortString.string[size] = 0; m_data.shortString.string[size] = 0;
m_data.shortString.control.setShortStringSize(size); m_data.shortString.control.setShortStringSize(size);
m_data.shortString.control.setIsShortString(true); m_data.shortString.control.setIsShortString(true);
m_data.shortString.control.setIsReadOnlyReference(false); m_data.shortString.control.setIsReadOnlyReference(false);
} else { } else {
m_data.allocated.data.pointer = Memory::allocate(capacity + 1); m_data.allocated.data.pointer = Memory::allocate(capacity + 1);
std::memcpy(m_data.allocated.data.pointer, string, size); std::char_traits<char>::copy(m_data.allocated.data.pointer, string, size);
initializeLongString(size, capacity); initializeLongString(size, capacity);
} }
} }
explicit BasicSmallString(SmallStringView stringView) explicit BasicSmallString(SmallStringView stringView)
: BasicSmallString(stringView.data(), stringView.size(), stringView.size()) : BasicSmallString(stringView.data(), stringView.size(), stringView.size())
{ {}
}
BasicSmallString(const char *string, size_type size) BasicSmallString(const char *string, size_type size)
: BasicSmallString(string, size, size) : BasicSmallString(string, size, size)
{ {
} }
template<typename Type, template<typename Type, typename = std::enable_if_t<std::is_pointer<Type>::value>>
typename = std::enable_if_t<std::is_pointer<Type>::value>
>
BasicSmallString(Type characterPointer) BasicSmallString(Type characterPointer)
: BasicSmallString(characterPointer, std::strlen(characterPointer)) : BasicSmallString(characterPointer, std::char_traits<char>::length(characterPointer))
{ {
static_assert(!std::is_array<Type>::value, "Input type is array and not char pointer!"); static_assert(!std::is_array<Type>::value, "Input type is array and not char pointer!");
} }
@@ -211,8 +207,7 @@ public:
return clonedString; return clonedString;
} }
friend friend void swap(BasicSmallString &first, BasicSmallString &second) noexcept
void swap(BasicSmallString &first, BasicSmallString &second)
{ {
using std::swap; using std::swap;
@@ -254,7 +249,7 @@ public:
static static
BasicSmallString fromUtf8(const char *characterPointer) BasicSmallString fromUtf8(const char *characterPointer)
{ {
return BasicSmallString(characterPointer, std::strlen(characterPointer)); return BasicSmallString(characterPointer, std::char_traits<char>::length(characterPointer));
} }
void reserve(size_type newCapacity) void reserve(size_type newCapacity)
@@ -272,7 +267,7 @@ public:
const char *oldData = data(); const char *oldData = data();
char *newData = Memory::allocate(newCapacity + 1); char *newData = Memory::allocate(newCapacity + 1);
std::memcpy(newData, oldData, oldSize); std::char_traits<char>::copy(newData, oldData, oldSize);
m_data.allocated.data.pointer = newData; m_data.allocated.data.pointer = newData;
initializeLongString(oldSize, newCapacity); initializeLongString(oldSize, newCapacity);
} }
@@ -381,7 +376,7 @@ public:
bool contains(char characterToSearch) const bool contains(char characterToSearch) const
{ {
auto found = std::memchr(data(), characterToSearch, size()); auto found = std::char_traits<char>::find(data(), size(), characterToSearch);
return found != nullptr; return found != nullptr;
} }
@@ -389,7 +384,9 @@ public:
bool startsWith(SmallStringView subStringToSearch) const noexcept bool startsWith(SmallStringView subStringToSearch) const noexcept
{ {
if (size() >= subStringToSearch.size()) if (size() >= subStringToSearch.size())
return !std::memcmp(data(), subStringToSearch.data(), subStringToSearch.size()); return !std::char_traits<char>::compare(data(),
subStringToSearch.data(),
subStringToSearch.size());
return false; return false;
} }
@@ -402,7 +399,8 @@ public:
bool endsWith(SmallStringView subStringToSearch) const noexcept bool endsWith(SmallStringView subStringToSearch) const noexcept
{ {
if (size() >= subStringToSearch.size()) { if (size() >= subStringToSearch.size()) {
const int comparison = std::memcmp(end().data() - subStringToSearch.size(), const int comparison = std::char_traits<char>::compare(end().data()
- subStringToSearch.size(),
subStringToSearch.data(), subStringToSearch.data(),
subStringToSearch.size()); subStringToSearch.size());
return comparison == 0; return comparison == 0;
@@ -463,7 +461,7 @@ public:
size_type newSize = oldSize + string.size(); size_type newSize = oldSize + string.size();
reserve(optimalCapacity(newSize)); reserve(optimalCapacity(newSize));
std::memcpy(data() + oldSize, string.data(), string.size()); std::char_traits<char>::copy(data() + oldSize, string.data(), string.size());
at(newSize) = 0; at(newSize) = 0;
setSize(newSize); setSize(newSize);
} }
@@ -725,7 +723,7 @@ private:
at(size) = 0; at(size) = 0;
} }
void initializeLongString(size_type size, size_type capacity) constexpr void initializeLongString(size_type size, size_type capacity)
{ {
m_data.allocated.data.pointer[size] = 0; m_data.allocated.data.pointer[size] = 0;
m_data.allocated.data.size = size; m_data.allocated.data.size = size;
@@ -758,7 +756,7 @@ private:
while (found != end()) { while (found != end()) {
start = found + toText.size(); start = found + toText.size();
std::memcpy(found.data(), toText.data(), toText.size()); std::char_traits<char>::copy(found.data(), toText.data(), toText.size());
found = std::search(start, found = std::search(start,
end(), end(),

View File

@@ -25,6 +25,18 @@
#pragma once #pragma once
#if __cplusplus >= 201703L
#define constexpr17 constexpr
#else
#define constexpr17 inline
#endif
#if __cplusplus >= 202002L
#define constexpr20 constexpr
#else
#define constexpr20 inline
#endif
using uint = unsigned int; using uint = unsigned int;
namespace Utils { namespace Utils {
@@ -35,9 +47,4 @@ class BasicSmallString;
using SmallString = BasicSmallString<31>; using SmallString = BasicSmallString<31>;
using PathString = BasicSmallString<190>; using PathString = BasicSmallString<190>;
inline
int compare(SmallStringView first, SmallStringView second) noexcept;
inline
int reverseCompare(SmallStringView first, SmallStringView second) noexcept;
} // namespace Utils } // namespace Utils

View File

@@ -230,30 +230,6 @@ QDataStream &operator>>(QDataStream &in, vector<Type> &vector)
return in; return in;
} }
template <typename T>
ostream &operator<<(ostream &out, const vector<T> &vector)
{
out << "[";
for (auto current = vector.begin(); current != vector.end(); ++current) {
std::ostringstream entryStream;
entryStream << *current;
std::string entryString = entryStream.str();
if (entryString.size() > 4)
out << "\n\t";
out << entryString;
if (std::next(current) != vector.end())
out << ", ";
}
out << "]";
return out;
}
} // namespace std } // namespace std
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE

View File

@@ -37,118 +37,89 @@ template <class Category,
typename DistanceType = ptrdiff_t, typename DistanceType = ptrdiff_t,
typename Pointer = Type *, typename Pointer = Type *,
typename Reference = Type &> typename Reference = Type &>
struct SmallStringIterator : public std::iterator<Category, Type, DistanceType, Pointer, Reference> struct SmallStringIterator
{ {
constexpr using iterator_category = Category;
SmallStringIterator() noexcept = default; using value_type = Type;
using difference_type = DistanceType;
using pointer = Pointer;
using reference = Reference;
constexpr constexpr SmallStringIterator() noexcept = default;
SmallStringIterator(Pointer ptr) noexcept : pointer_(ptr)
{
}
SmallStringIterator operator++() noexcept constexpr SmallStringIterator(Pointer ptr) noexcept
{ : pointer_(ptr)
return ++pointer_; {}
}
SmallStringIterator operator++(int) noexcept constexpr SmallStringIterator operator++() noexcept { return ++pointer_; }
{
return pointer_++;
}
SmallStringIterator operator--() noexcept constexpr SmallStringIterator operator++(int) noexcept { return pointer_++; }
{
return --pointer_;
}
SmallStringIterator operator--(int) noexcept constexpr SmallStringIterator operator--() noexcept { return --pointer_; }
{
return pointer_--;
}
SmallStringIterator operator+(DistanceType difference) const noexcept constexpr SmallStringIterator operator--(int) noexcept { return pointer_--; }
constexpr SmallStringIterator operator+(DistanceType difference) const noexcept
{ {
return pointer_ + difference; return pointer_ + difference;
} }
SmallStringIterator operator-(DistanceType difference) const noexcept constexpr SmallStringIterator operator-(DistanceType difference) const noexcept
{ {
return pointer_ - difference; return pointer_ - difference;
} }
SmallStringIterator operator+(std::size_t difference) const noexcept constexpr SmallStringIterator operator+(std::size_t difference) const noexcept
{ {
return pointer_ + difference; return pointer_ + difference;
} }
SmallStringIterator operator-(std::size_t difference) const noexcept constexpr SmallStringIterator operator-(std::size_t difference) const noexcept
{ {
return pointer_ - difference; return pointer_ - difference;
} }
DistanceType operator-(SmallStringIterator other) const noexcept constexpr DistanceType operator-(SmallStringIterator other) const noexcept
{ {
return pointer_ - other.data(); return pointer_ - other.data();
} }
SmallStringIterator operator+=(DistanceType difference) noexcept constexpr SmallStringIterator operator+=(DistanceType difference) noexcept
{ {
return pointer_ += difference; return pointer_ += difference;
} }
SmallStringIterator operator-=(DistanceType difference) noexcept constexpr SmallStringIterator operator-=(DistanceType difference) noexcept
{ {
return pointer_ -= difference; return pointer_ -= difference;
} }
Reference operator*() noexcept constexpr Reference operator*() noexcept { return *pointer_; }
{
return *pointer_;
}
const Reference operator*() const noexcept const Reference operator*() const noexcept { return *pointer_; }
{
return *pointer_;
}
Pointer operator->() noexcept constexpr Pointer operator->() noexcept { return pointer_; }
{
return pointer_;
}
const Pointer operator->() const noexcept constexpr const Pointer operator->() const noexcept { return pointer_; }
{
return pointer_;
}
constexpr constexpr bool operator==(SmallStringIterator other) const noexcept
bool operator==(SmallStringIterator other) const noexcept
{ {
return pointer_ == other.pointer_; return pointer_ == other.pointer_;
} }
constexpr constexpr bool operator!=(SmallStringIterator other) const noexcept
bool operator!=(SmallStringIterator other) const noexcept
{ {
return pointer_ != other.pointer_; return pointer_ != other.pointer_;
} }
constexpr constexpr bool operator<(SmallStringIterator other) const noexcept
bool operator<(SmallStringIterator other) const noexcept
{ {
return pointer_ < other.pointer_; return pointer_ < other.pointer_;
} }
Pointer data() noexcept constexpr Pointer data() noexcept { return pointer_; }
{
return pointer_;
}
const Pointer data() const noexcept constexpr const Pointer data() const noexcept { return pointer_; }
{
return pointer_;
}
private: private:
Pointer pointer_ = nullptr; Pointer pointer_ = nullptr;

View File

@@ -49,30 +49,21 @@ struct ControlBlock
m_isReference(isReference) m_isReference(isReference)
{} {}
void setShortStringSize(size_type size) constexpr void setShortStringSize(size_type size)
{ {
m_shortStringSize = static_cast<SizeType>(size); m_shortStringSize = static_cast<SizeType>(size);
} }
size_type shortStringSize() const constexpr size_type shortStringSize() const { return m_shortStringSize; }
{
return m_shortStringSize;
}
void setIsReadOnlyReference(bool isReadOnlyReference) constexpr void setIsReadOnlyReference(bool isReadOnlyReference)
{ {
m_isReadOnlyReference = isReadOnlyReference; m_isReadOnlyReference = isReadOnlyReference;
} }
void setIsReference(bool isReference) constexpr void setIsReference(bool isReference) { m_isReference = isReference; }
{
m_isReference = isReference;
}
void setIsShortString(bool isShortString) constexpr void setIsShortString(bool isShortString) { m_isReference = !isShortString; }
{
m_isReference = !isShortString;
}
constexpr constexpr
SizeType stringSize() const SizeType stringSize() const
@@ -168,7 +159,7 @@ struct StringDataLayout {
template<size_type Size, template<size_type Size,
typename std::enable_if_t<Size <= MaximumShortStringDataAreaSize, int> = 0> typename std::enable_if_t<Size <= MaximumShortStringDataAreaSize, int> = 0>
StringDataLayout(const char(&string)[Size]) noexcept constexpr StringDataLayout(const char (&string)[Size]) noexcept
: shortString(ShortStringLayout<MaximumShortStringDataAreaSize>{}) : shortString(ShortStringLayout<MaximumShortStringDataAreaSize>{})
{ {
for (size_type i = 0; i < Size; ++i) for (size_type i = 0; i < Size; ++i)

View File

@@ -37,34 +37,24 @@ namespace Memory {
inline char *allocate(std::size_t size) inline char *allocate(std::size_t size)
{ {
#ifdef Q_OS_WIN32
return static_cast<char*>(_aligned_malloc(size, 64));
#else
return static_cast<char*>(std::malloc(size)); return static_cast<char*>(std::malloc(size));
#endif
} }
inline void deallocate(char *memory) inline void deallocate(char *memory)
{ {
#ifdef Q_OS_WIN32
_aligned_free(memory);
#else
#pragma GCC diagnostic push
#if defined(__GNUC__) && !defined(__clang__) #if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfree-nonheap-object" #pragma GCC diagnostic ignored "-Wfree-nonheap-object"
#endif #endif
std::free(memory); std::free(memory);
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
} }
inline char *reallocate(char *oldMemory, std::size_t newSize) inline char *reallocate(char *oldMemory, std::size_t newSize)
{ {
#ifdef Q_OS_WIN32
return static_cast<char*>(_aligned_realloc(oldMemory, newSize, 64));
#else
return static_cast<char *>(std::realloc(oldMemory, newSize)); return static_cast<char *>(std::realloc(oldMemory, newSize));
#endif
} }
} // namespace Memory } // namespace Memory

View File

@@ -25,6 +25,7 @@
#pragma once #pragma once
#include "smallstringfwd.h"
#include "smallstringiterator.h" #include "smallstringiterator.h"
#include <QString> #include <QString>
@@ -53,49 +54,32 @@ public:
constexpr SmallStringView() = default; constexpr SmallStringView() = default;
template<size_type Size> constexpr17 SmallStringView(const char *characterPointer) noexcept
constexpr : m_pointer(characterPointer)
SmallStringView(const char(&string)[Size]) noexcept , m_size(std::char_traits<char>::length(characterPointer))
: m_pointer(string),
m_size(Size - 1)
{
static_assert(Size >= 1, "Invalid string literal! Length is zero!");
}
template<typename Type,
typename = std::enable_if_t<std::is_pointer<Type>::value>
>
SmallStringView(Type characterPointer) noexcept
: m_pointer(characterPointer),
m_size(std::strlen(characterPointer))
{
static_assert(!std::is_array<Type>::value, "Input type is array and not char pointer!");
}
constexpr
SmallStringView(const char *const string, const size_type size) noexcept
: m_pointer(string),
m_size(size)
{
}
SmallStringView(const const_iterator begin, const const_iterator end) noexcept
: m_pointer(begin.data()),
m_size(std::size_t(end - begin))
{
}
template<typename String,
typename Utils::enable_if_has_char_data_pointer<String> = 0>
SmallStringView(const String &string) noexcept
: m_pointer(string.data()),
m_size(string.size())
{} {}
static constexpr SmallStringView(const char *const string, const size_type size) noexcept
SmallStringView fromUtf8(const char *const characterPointer) : m_pointer(string)
, m_size(size)
{ {
return SmallStringView(characterPointer, std::strlen(characterPointer)); }
constexpr SmallStringView(const const_iterator begin, const const_iterator end) noexcept
: m_pointer(begin.data())
, m_size(std::size_t(end - begin))
{
}
template<typename String, typename Utils::enable_if_has_char_data_pointer<String> = 0>
constexpr SmallStringView(const String &string) noexcept
: m_pointer(string.data())
, m_size(string.size())
{}
static constexpr17 SmallStringView fromUtf8(const char *const characterPointer)
{
return SmallStringView(characterPointer);
} }
constexpr constexpr
@@ -146,93 +130,85 @@ public:
return data() + size(); return data() + size();
} }
const_reverse_iterator rbegin() const noexcept constexpr17 const_reverse_iterator rbegin() const noexcept
{ {
return const_reverse_iterator(end()); return const_reverse_iterator(end());
} }
const_reverse_iterator rend() const noexcept constexpr17 const_reverse_iterator rend() const noexcept
{ {
return const_reverse_iterator(begin()); return const_reverse_iterator(begin());
} }
operator std::string() const constexpr20 operator std::string() const { return std::string(data(), size()); }
{
return std::string(data(), size());
}
explicit operator QString() const explicit operator QString() const
{ {
return QString::fromUtf8(data(), int(size())); return QString::fromUtf8(data(), int(size()));
} }
bool startsWith(SmallStringView subStringToSearch) const noexcept constexpr17 bool startsWith(SmallStringView subStringToSearch) const noexcept
{ {
if (size() >= subStringToSearch.size()) if (size() >= subStringToSearch.size())
return !std::memcmp(m_pointer, subStringToSearch.data(), subStringToSearch.size()); return !std::char_traits<char>::compare(m_pointer,
subStringToSearch.data(),
subStringToSearch.size());
return false; return false;
} }
bool startsWith(char characterToSearch) const noexcept constexpr bool startsWith(char characterToSearch) const noexcept
{ {
return m_pointer[0] == characterToSearch; return m_pointer[0] == characterToSearch;
} }
char back() const { return m_pointer[m_size - 1]; } constexpr char back() const { return m_pointer[m_size - 1]; }
char operator[](std::size_t index) { return m_pointer[index]; } constexpr char operator[](std::size_t index) { return m_pointer[index]; }
private: private:
const char *m_pointer = ""; const char *m_pointer = "";
size_type m_size = 0; size_type m_size = 0;
}; };
inline constexpr17 bool operator==(SmallStringView first, SmallStringView second) noexcept
bool operator==(SmallStringView first, SmallStringView second) noexcept
{ {
return first.size() == second.size() && std::memcmp(first.data(), second.data(), first.size()) == 0; return first.size() == second.size()
&& std::char_traits<char>::compare(first.data(), second.data(), first.size()) == 0;
} }
inline constexpr17 bool operator!=(SmallStringView first, SmallStringView second) noexcept
bool operator!=(SmallStringView first, SmallStringView second) noexcept
{ {
return !(first == second); return !(first == second);
} }
inline constexpr17 int compare(SmallStringView first, SmallStringView second) noexcept
int compare(SmallStringView first, SmallStringView second) noexcept
{ {
int sizeDifference = int(first.size() - second.size()); int sizeDifference = int(first.size() - second.size());
if (sizeDifference == 0) if (sizeDifference == 0)
return std::memcmp(first.data(), second.data(), first.size()); return std::char_traits<char>::compare(first.data(), second.data(), first.size());
return sizeDifference; return sizeDifference;
} }
inline constexpr17 bool operator<(SmallStringView first, SmallStringView second) noexcept
bool operator<(SmallStringView first, SmallStringView second) noexcept
{ {
return compare(first, second) < 0; return compare(first, second) < 0;
} }
inline constexpr17 bool operator>(SmallStringView first, SmallStringView second) noexcept
bool operator>(SmallStringView first, SmallStringView second) noexcept
{ {
return second < first; return second < first;
} }
namespace Internal { namespace Internal {
inline constexpr int reverse_memcmp(const char *first, const char *second, size_t n)
int reverse_memcmp(const char *first, const char *second, size_t n)
{ {
const char *currentFirst = first + n - 1; const char *currentFirst = first + n - 1;
const char *currentSecond = second + n - 1; const char *currentSecond = second + n - 1;
while (n > 0) while (n > 0) {
{
// If the current characters differ, return an appropriately signed // If the current characters differ, return an appropriately signed
// value; otherwise, keep searching backwards // value; otherwise, keep searching backwards
int difference = *currentFirst - *currentSecond; int difference = *currentFirst - *currentSecond;
@@ -246,10 +222,9 @@ int reverse_memcmp(const char *first, const char *second, size_t n)
return 0; return 0;
} }
} } // namespace Internal
inline constexpr int reverseCompare(SmallStringView first, SmallStringView second) noexcept
int reverseCompare(SmallStringView first, SmallStringView second) noexcept
{ {
int sizeDifference = int(first.size() - second.size()); int sizeDifference = int(first.size() - second.size());
@@ -261,10 +236,7 @@ int reverseCompare(SmallStringView first, SmallStringView second) noexcept
} // namespace Utils } // namespace Utils
#ifdef __cpp_user_defined_literals
inline
constexpr Utils::SmallStringView operator""_sv(const char *const string, size_t size) constexpr Utils::SmallStringView operator""_sv(const char *const string, size_t size)
{ {
return Utils::SmallStringView(string, size); return Utils::SmallStringView(string, size);
} }
#endif

40
src/libs/utils/span.h Normal file
View 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

View File

@@ -152,6 +152,8 @@ HEADERS += \
$$PWD/pointeralgorithm.h \ $$PWD/pointeralgorithm.h \
$$PWD/qrcparser.h \ $$PWD/qrcparser.h \
$$PWD/qtcprocess.h \ $$PWD/qtcprocess.h \
$$PWD/span.h \
$$PWD/../3rdparty/span/span.hpp \
$$PWD/utils_global.h \ $$PWD/utils_global.h \
$$PWD/reloadpromptutils.h \ $$PWD/reloadpromptutils.h \
$$PWD/settingsaccessor.h \ $$PWD/settingsaccessor.h \

View File

@@ -245,6 +245,8 @@ Project {
"smallstringlayout.h", "smallstringlayout.h",
"smallstringmemory.h", "smallstringmemory.h",
"smallstringvector.h", "smallstringvector.h",
"span.h",
"../3rdparty/span/span.hpp",
"statuslabel.cpp", "statuslabel.cpp",
"statuslabel.h", "statuslabel.h",
"stringutils.cpp", "stringutils.cpp",

View File

@@ -37,6 +37,7 @@ using std::get;
using std::get_if; using std::get_if;
using std::holds_alternative; using std::holds_alternative;
using std::variant; using std::variant;
using std::visit;
} // namespace Utils } // namespace Utils
#else #else
@@ -47,6 +48,7 @@ using mpark::get;
using mpark::get_if; using mpark::get_if;
using mpark::holds_alternative; using mpark::holds_alternative;
using mpark::variant; using mpark::variant;
using mpark::visit;
} // namespace Utils } // namespace Utils
#endif #endif

View File

@@ -134,6 +134,8 @@ extend_qtc_plugin(QmlDesigner
reparentinstancescommand.cpp reparentinstancescommand.h reparentinstancescommand.cpp reparentinstancescommand.h
statepreviewimagechangedcommand.cpp statepreviewimagechangedcommand.h statepreviewimagechangedcommand.cpp statepreviewimagechangedcommand.h
synchronizecommand.cpp synchronizecommand.h synchronizecommand.cpp synchronizecommand.h
changepreviewimagesizecommand.cpp changepreviewimagesizecommand.h
changelanguagecommand.cpp changelanguagecommand.h
tokencommand.cpp tokencommand.h tokencommand.cpp tokencommand.h
valueschangedcommand.cpp valueschangedcommand.h valueschangedcommand.cpp valueschangedcommand.h
changeselectioncommand.cpp changeselectioncommand.h changeselectioncommand.cpp changeselectioncommand.h
@@ -457,6 +459,7 @@ extend_qtc_plugin(QmlDesigner
include/rewriterview.h include/rewriterview.h
include/rewritingexception.h include/rewritingexception.h
include/signalhandlerproperty.h include/signalhandlerproperty.h
include/stylesheetmerger.h
include/subcomponentmanager.h include/subcomponentmanager.h
include/textmodifier.h include/textmodifier.h
include/variantproperty.h include/variantproperty.h
@@ -530,6 +533,7 @@ extend_qtc_plugin(QmlDesigner
model/rewriteactioncompressor.cpp model/rewriteactioncompressor.h model/rewriteactioncompressor.cpp model/rewriteactioncompressor.h
model/rewriterview.cpp model/rewriterview.cpp
model/signalhandlerproperty.cpp model/signalhandlerproperty.cpp
model/stylesheetmerger.cpp
model/textmodifier.cpp model/textmodifier.cpp
model/texttomodelmerger.cpp model/texttomodelmerger.h model/texttomodelmerger.cpp model/texttomodelmerger.h
model/variantproperty.cpp model/variantproperty.cpp
@@ -557,6 +561,7 @@ extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/annotationeditor SOURCES_PREFIX components/annotationeditor
SOURCES annotationcommenttab.cpp annotationcommenttab.h annotationcommenttab.ui SOURCES annotationcommenttab.cpp annotationcommenttab.h annotationcommenttab.ui
annotationeditordialog.cpp annotationeditordialog.h annotationeditordialog.ui annotationeditordialog.cpp annotationeditordialog.h annotationeditordialog.ui
globalannotationeditordialog.cpp globalannotationeditordialog.h globalannotationeditordialog.ui
annotationeditor.cpp annotationeditor.h annotationeditor.cpp annotationeditor.h
annotationtool.cpp annotationtool.h annotationtool.cpp annotationtool.h
globalannotationeditor.cpp globalannotationeditor.h globalannotationeditor.cpp globalannotationeditor.h

View File

@@ -79,7 +79,7 @@ void AnnotationCommentTab::resetUI()
{ {
ui->titleEdit->setText(m_comment.title()); ui->titleEdit->setText(m_comment.title());
ui->authorEdit->setText(m_comment.author()); ui->authorEdit->setText(m_comment.author());
m_editor->setRichText(m_comment.text()); m_editor->setRichText(m_comment.deescapedText());
if (m_comment.timestamp() > 0) if (m_comment.timestamp() > 0)
ui->timeLabel->setText(m_comment.timestampStr()); ui->timeLabel->setText(m_comment.timestampStr());

View File

@@ -3,12 +3,15 @@ HEADERS += $$PWD/annotationcommenttab.h
HEADERS += $$PWD/annotationeditordialog.h HEADERS += $$PWD/annotationeditordialog.h
HEADERS += $$PWD/annotationeditor.h HEADERS += $$PWD/annotationeditor.h
HEADERS += $$PWD/globalannotationeditor.h HEADERS += $$PWD/globalannotationeditor.h
HEADERS += $$PWD/globalannotationeditordialog.h
SOURCES += $$PWD/annotationtool.cpp SOURCES += $$PWD/annotationtool.cpp
SOURCES += $$PWD/annotationcommenttab.cpp SOURCES += $$PWD/annotationcommenttab.cpp
SOURCES += $$PWD/annotationeditordialog.cpp SOURCES += $$PWD/annotationeditordialog.cpp
SOURCES += $$PWD/annotationeditor.cpp SOURCES += $$PWD/annotationeditor.cpp
SOURCES += $$PWD/globalannotationeditor.cpp SOURCES += $$PWD/globalannotationeditor.cpp
SOURCES += $$PWD/globalannotationeditordialog.cpp
FORMS += $$PWD/annotationcommenttab.ui FORMS += $$PWD/annotationcommenttab.ui
FORMS += $$PWD/annotationeditordialog.ui FORMS += $$PWD/annotationeditordialog.ui
FORMS += $$PWD/globalannotationeditordialog.ui

View File

@@ -40,12 +40,11 @@
namespace QmlDesigner { namespace QmlDesigner {
AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation, EditorMode mode) AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::AnnotationEditorDialog) , ui(new Ui::AnnotationEditorDialog)
, m_customId(customId) , m_customId(customId)
, m_annotation(annotation) , m_annotation(annotation)
, m_editorMode(mode)
{ {
ui->setupUi(this); ui->setupUi(this);
@@ -98,8 +97,8 @@ AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &t
ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner); ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner);
ui->targetIdEdit->setText(targetId); ui->targetIdEdit->setText(targetId);
changeEditorMode(m_editorMode);
fillFields(); fillFields();
setWindowTitle(annotationEditorTitle);
} }
AnnotationEditorDialog::~AnnotationEditorDialog() AnnotationEditorDialog::~AnnotationEditorDialog()
@@ -129,39 +128,6 @@ QString AnnotationEditorDialog::customId() const
return m_customId; return m_customId;
} }
void AnnotationEditorDialog::changeEditorMode(AnnotationEditorDialog::EditorMode mode)
{
switch (mode) {
case ItemAnnotation: {
ui->customIdEdit->setVisible(true);
ui->customIdLabel->setVisible(true);
ui->targetIdEdit->setVisible(true);
ui->targetIdLabel->setVisible(true);
setWindowTitle(annotationEditorTitle);
break;
}
case GlobalAnnotation: {
ui->customIdEdit->clear();
ui->targetIdEdit->clear();
ui->customIdEdit->setVisible(false);
ui->customIdLabel->setVisible(false);
ui->targetIdEdit->setVisible(false);
ui->targetIdLabel->setVisible(false);
setWindowTitle(globalEditorTitle);
break;
}
}
m_editorMode = mode;
}
AnnotationEditorDialog::EditorMode AnnotationEditorDialog::editorMode() const
{
return m_editorMode;
}
void AnnotationEditorDialog::acceptedClicked() void AnnotationEditorDialog::acceptedClicked()
{ {
m_customId = ui->customIdEdit->text(); m_customId = ui->customIdEdit->text();

View File

@@ -40,10 +40,7 @@ class AnnotationEditorDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
enum EditorMode { ItemAnnotation, GlobalAnnotation }; explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation);
explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation,
EditorMode mode = EditorMode::ItemAnnotation);
~AnnotationEditorDialog(); ~AnnotationEditorDialog();
void setAnnotation(const Annotation &annotation); void setAnnotation(const Annotation &annotation);
@@ -52,9 +49,6 @@ public:
void setCustomId(const QString &customId); void setCustomId(const QString &customId);
QString customId() const; QString customId() const;
void changeEditorMode(EditorMode mode);
EditorMode editorMode() const;
signals: signals:
void accepted(); void accepted();
@@ -75,14 +69,11 @@ private:
private: private:
const QString annotationEditorTitle = {tr("Annotation Editor")}; const QString annotationEditorTitle = {tr("Annotation Editor")};
const QString globalEditorTitle = {tr("Global Annotation Editor")};
const QString defaultTabName = {tr("Annotation")}; const QString defaultTabName = {tr("Annotation")};
Ui::AnnotationEditorDialog *ui; Ui::AnnotationEditorDialog *ui;
QString m_customId; QString m_customId;
Annotation m_annotation; Annotation m_annotation;
EditorMode m_editorMode;
}; };
} //namespace QmlDesigner } //namespace QmlDesigner

View File

@@ -6,15 +6,16 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1100</width> <width>1344</width>
<height>600</height> <height>819</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string notr="true">Dialog</string> <string notr="true">Dialog</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QWidget" name="annotationContainer" native="true">
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<layout class="QHBoxLayout" name="targetIdLayout"> <layout class="QHBoxLayout" name="targetIdLayout">
@@ -52,6 +53,7 @@
</layout> </layout>
</item> </item>
</layout> </layout>
</widget>
</item> </item>
<item> <item>
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">

View File

@@ -25,7 +25,7 @@
#include "globalannotationeditor.h" #include "globalannotationeditor.h"
#include "annotationeditordialog.h" #include "globalannotationeditordialog.h"
#include "annotation.h" #include "annotation.h"
#include "qmlmodelnodeproxy.h" #include "qmlmodelnodeproxy.h"
@@ -49,15 +49,13 @@ GlobalAnnotationEditor::~GlobalAnnotationEditor()
void GlobalAnnotationEditor::showWidget() void GlobalAnnotationEditor::showWidget()
{ {
m_dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(), m_dialog = new GlobalAnnotationEditorDialog(Core::ICore::dialogParent(),
modelNode().validId(),
"",
modelNode().globalAnnotation(), modelNode().globalAnnotation(),
AnnotationEditorDialog::EditorMode::GlobalAnnotation); modelNode().globalStatus());
QObject::connect(m_dialog, &AnnotationEditorDialog::accepted, QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::accepted,
this, &GlobalAnnotationEditor::acceptedClicked); this, &GlobalAnnotationEditor::acceptedClicked);
QObject::connect(m_dialog, &AnnotationEditorDialog::rejected, QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::rejected,
this, &GlobalAnnotationEditor::cancelClicked); this, &GlobalAnnotationEditor::cancelClicked);
m_dialog->setAttribute(Qt::WA_DeleteOnClose); m_dialog->setAttribute(Qt::WA_DeleteOnClose);
@@ -121,12 +119,24 @@ void GlobalAnnotationEditor::removeFullAnnotation()
void GlobalAnnotationEditor::acceptedClicked() void GlobalAnnotationEditor::acceptedClicked()
{ {
if (m_dialog) { if (m_dialog) {
Annotation annotation = m_dialog->annotation(); Annotation annotation = m_dialog->annotation();
if (annotation.comments().isEmpty()) if (annotation.comments().isEmpty())
m_modelNode.removeGlobalAnnotation(); m_modelNode.removeGlobalAnnotation();
else else
m_modelNode.setGlobalAnnotation(annotation); m_modelNode.setGlobalAnnotation(annotation);
GlobalAnnotationStatus status = m_dialog->globalStatus();
if (status.status() == GlobalAnnotationStatus::NoStatus) {
if (m_modelNode.hasGlobalStatus()) {
m_modelNode.removeGlobalStatus();
}
}
else {
m_modelNode.setGlobalStatus(status);
}
} }
hideWidget(); hideWidget();

View File

@@ -29,7 +29,7 @@
#include <QtQml> #include <QtQml>
#include <QPointer> #include <QPointer>
#include "annotationeditordialog.h" #include "globalannotationeditordialog.h"
#include "annotation.h" #include "annotation.h"
#include "modelnode.h" #include "modelnode.h"
@@ -67,7 +67,7 @@ private slots:
void cancelClicked(); void cancelClicked();
private: private:
QPointer<AnnotationEditorDialog> m_dialog; QPointer<GlobalAnnotationEditorDialog> m_dialog;
ModelNode m_modelNode; ModelNode m_modelNode;
}; };

View File

@@ -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

View File

@@ -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

View File

@@ -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>

Some files were not shown because too many files have changed in this diff Show More