Merge "Merge remote-tracking branch 'origin/4.15'"

This commit is contained in:
The Qt Project
2021-03-09 14:33:44 +00:00
54 changed files with 574 additions and 291 deletions

View File

@@ -844,39 +844,7 @@ class Dumper(DumperBase):
if typeobj is not None:
return typeobj
return self.lookupNativeTypeInAllModules(name)
def lookupNativeTypeInAllModules(self, name):
needle = self.canonicalTypeName(name)
#DumperBase.warn('NEEDLE: %s ' % needle)
DumperBase.warn('Searching for type %s across all target modules, this could be very slow' % name)
for i in range(self.target.GetNumModules()):
module = self.target.GetModuleAtIndex(i)
# SBModule.GetType is new somewhere after early 300.x
# So this may fail.
for t in module.GetTypes():
n = self.canonicalTypeName(t.GetName())
#DumperBase.warn('N: %s' % n)
if n == needle:
#DumperBase.warn('FOUND TYPE DIRECT 2: %s ' % t)
self.typeCache[name] = t
return t
if n == needle + '*':
res = t.GetPointeeType()
self.typeCache[name] = res
x = self.fromNativeType(res) # Register under both names
self.registerTypeAlias(x.typeId, name)
#DumperBase.warn('FOUND TYPE BY POINTER: %s ' % res.name)
return res
if n == needle + '&':
res = t.GetDereferencedType().GetUnqualifiedType()
self.typeCache[name] = res
x = self.fromNativeType(res) # Register under both names
self.registerTypeAlias(x.typeId, name)
#DumperBase.warn('FOUND TYPE BY REFERENCE: %s ' % res.name)
return res
#DumperBase.warn('NOT FOUND: %s ' % needle)
return None
return lldb.SBType()
def setupInferior(self, args):
""" Set up SBTarget instance """
@@ -904,14 +872,6 @@ class Dumper(DumperBase):
except: # Could have been deleted in the mean time.
pass
self.ignoreStops = 0
if platform.system() == 'Linux':
if self.startMode_ == DebuggerStartMode.AttachCore:
pass
else:
if self.useTerminal_:
self.ignoreStops = 1
if self.platform_:
self.debugger.SetCurrentPlatform(self.platform_)
# sysroot has to be set *after* the platform
@@ -1450,9 +1410,6 @@ class Dumper(DumperBase):
if self.isInterrupting_:
self.isInterrupting_ = False
self.reportState("inferiorstopok")
elif self.ignoreStops > 0:
self.ignoreStops -= 1
self.process.Continue()
else:
self.reportState("stopped")
else:
@@ -2086,10 +2043,6 @@ class SummaryDumper(Dumper, LogMixin):
def report(self, stuff):
return # Don't mess up lldb output
def lookupNativeTypeInAllModules(self, name):
self.warn('Failed to resolve type %s' % name)
return None
def dump_summary(self, valobj, expanded=False):
try:
from pygdbmi import gdbmiparser

View File

@@ -30,8 +30,6 @@ import QtQuickDesignerTheme 1.0
Column {
id: root
signal addImport(int index)
Text {
id: header
text: qsTr("Select a Module to Add")
@@ -78,7 +76,7 @@ Column {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: addImport(index)
onClicked: rootView.handleAddImport(index)
enabled: !isSeparator
}
}

View File

@@ -87,6 +87,12 @@ ScrollView {
itemContextMenu.close()
}
onContentHeightChanged: {
var maxPosition = Math.max(contentHeight - height, 0)
if (contentY > maxPosition)
contentY = maxPosition
}
Item {
id: styleConstants
property int textWidth: 58

View File

@@ -26,17 +26,14 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuickDesignerTheme 1.0
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
Item {
id: root
width: 200
height: 75
signal tabChanged(int index)
signal filterChanged(string filterText)
signal addModuleClicked()
signal addAssetClicked()
function setTab(index)
{
tabBar.setCurrentIndex(index);
@@ -69,46 +66,60 @@ Item {
{title: qsTr("Assets"), addToolTip: qsTr("Add new assets to project.")}]
TabButton {
contentItem: Text { // TabButton text
topPadding: 4
bottomPadding: 4
contentItem: Item {
implicitHeight: plusButton.height
Text { // TabButton text
text: modelData.title
font.pixelSize: 13
font.bold: true
color: tabBar.currentIndex === index ? "#0094ce" : "#dadada"
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: plusButton.left
anchors.bottomMargin: 2
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignBottom
elide: Text.ElideRight
}
background: Item { // TabButton background
Rectangle { // + button
id: plusButton
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: 2
anchors.bottomMargin: 2
width: img.width + 10
height: img.height + 10
anchors.top: parent.top
anchors.topMargin: 1
width: 24
height: 24
color: mouseArea.containsMouse ? "#353535" : "#262626"
ToolTip.delay: 500
ToolTip.text: modelData.addToolTip
ToolTip.visible: mouseArea.containsMouse
Image {
id: img
source: tabBar.currentIndex === index ? "../images/add.png"
: "../images/add_unselected.png"
Label { // + sign
text: StudioTheme.Constants.plus
font.family: StudioTheme.Constants.iconFont.family
font.pixelSize: StudioTheme.Values.myIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
anchors.centerIn: parent
color: tabBar.currentIndex === index ? "#0094ce" : "#a8a8a8"
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: index == 0 ? addModuleClicked() : addAssetClicked()
onClicked: index == 0 ? rootView.handleAddModule()
: rootView.handleAddAsset()
}
}
}
background: Item { // TabButton background
Rectangle { // bottom strip
anchors.bottom: parent.bottom
width: parent.width
@@ -117,7 +128,7 @@ Item {
}
}
onClicked: tabChanged(index)
onClicked: rootView.handleTabChanged(index);
}
}
}
@@ -138,16 +149,30 @@ Item {
anchors.rightMargin: 5
selectByMouse: true
onTextChanged: filterChanged(text)
onTextChanged: rootView.handleSearchfilterChanged(text)
Image { // clear text button
source: "../images/x.png"
Rectangle { // x button
width: 15
height: 15
anchors.right: parent.right
anchors.rightMargin: 5
anchors.verticalCenter: parent.verticalCenter
visible: searchFilterText.text !== ""
color: xMouseArea.containsMouse ? "#353535" : "transparent"
Label {
text: StudioTheme.Constants.closeCross
font.family: StudioTheme.Constants.iconFont.family
font.pixelSize: StudioTheme.Values.myIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
anchors.centerIn: parent
color: "#dadada"
}
MouseArea {
id: xMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: searchFilterText.text = ""
}

View File

@@ -716,7 +716,7 @@ StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column)
break;
}
return StringType{"", 0};
return {};
}
} // namespace

View File

@@ -349,7 +349,7 @@ public:
bindValues(queryValues...);
while (BaseStatement::next())
pushBackToContainer<ResultTypeCount>(container);
emplaceBackValues<ResultTypeCount>(container);
resetter.reset();
}
@@ -448,19 +448,6 @@ private:
return callCallable(callable, std::make_integer_sequence<int, ResultTypeCount>{});
}
template<typename Container, int... ColumnIndices>
void pushBackToContainer(Container &container, std::integer_sequence<int, ColumnIndices...>)
{
using Type = typename Container::value_type;
container.push_back(Type(ValueGetter(*this, ColumnIndices)...));
}
template<int ResultTypeCount, typename Container>
void pushBackToContainer(Container &container)
{
pushBackToContainer(container, std::make_integer_sequence<int, ResultTypeCount>{});
}
template<typename ValueType>
void bindValuesByIndex(int index, const ValueType &value)
{

View File

@@ -611,6 +611,18 @@ bool ConsoleProcess::start()
return true;
}
void Utils::ConsoleProcess::kickoffProcess()
{
#ifdef Q_OS_WIN
// Not used.
#else
if (d->m_stubSocket && d->m_stubSocket->isWritable()) {
d->m_stubSocket->write("c", 1);
d->m_stubSocket->flush();
}
#endif
}
void ConsoleProcess::interruptProcess()
{
#ifdef Q_OS_WIN

View File

@@ -90,6 +90,7 @@ public:
bool isRunning() const; // This reflects the state of the console+stub
qint64 applicationPID() const;
void kickoffProcess();
void interruptProcess();
void killProcess();
void killStub();

View File

@@ -57,6 +57,7 @@ extern char **environ;
static int qtcFd;
static char *sleepMsg;
static int chldPipe[2];
static int blockingPipe[2];
static int isDebug;
static volatile int isDetached;
static volatile int chldPid;
@@ -236,10 +237,21 @@ int main(int argc, char *argv[])
perror("Cannot create status pipe");
doExit(3);
}
/* The debugged program is not supposed to inherit these handles. But we cannot
* close the writing end before calling exec(). Just handle both ends the same way ... */
fcntl(chldPipe[0], F_SETFD, FD_CLOEXEC);
fcntl(chldPipe[1], F_SETFD, FD_CLOEXEC);
if (isDebug) {
/* Create execution start notification pipe. The child waits on this until
the parent writes to it, triggered by an 'c' message from Creator */
if (pipe(blockingPipe)) {
perror("Cannot create blocking pipe");
doExit(3);
}
}
switch ((chldPid = fork())) {
case -1:
perror("Cannot fork child process");
@@ -262,9 +274,15 @@ int main(int argc, char *argv[])
#ifdef __linux__
prctl(PR_SET_PTRACER, atoi(argv[ArgPid]));
#endif
/* Stop the child to allow the debugger to attach */
if (isDebug)
kill(chldPid, SIGSTOP);
/* Block to allow the debugger to attach */
if (isDebug) {
char buf;
int res = read(blockingPipe[0], &buf, 1);
if (res < 0)
perror("Could not read from blocking pipe");
close(blockingPipe[0]);
close(blockingPipe[1]);
}
if (env)
environ = env;
@@ -296,6 +314,7 @@ int main(int argc, char *argv[])
break;
} else {
int i;
char c = 'i';
for (i = 0; i < nbytes; ++i) {
switch (buffer[i]) {
case 'k':
@@ -305,13 +324,12 @@ int main(int argc, char *argv[])
kill(chldPid, SIGKILL);
}
break;
case 'i':
if (chldPid > 0) {
int res = kill(chldPid, SIGINT);
if (res)
perror("Stub could not interrupt inferior");
}
case 'c': {
int res = write(blockingPipe[1], &c, 1);
if (res < 0)
perror("Could not write to blocking pipe");
break;
}
case 'd':
isDetached = 1;
break;

View File

@@ -64,8 +64,8 @@ template<uint Size>
class BasicSmallString
{
public:
using iterator = Internal::SmallStringIterator<std::random_access_iterator_tag, char>;
using const_iterator = Internal::SmallStringIterator<std::random_access_iterator_tag, const char>;
using iterator = SmallStringView::iterator;
using const_iterator = SmallStringView::const_iterator;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using size_type = std::size_t;
@@ -113,8 +113,15 @@ public:
BasicSmallString(const char *string, size_type size)
: BasicSmallString(string, size, size)
{
}
{}
explicit BasicSmallString(const_iterator begin, const_iterator end)
: BasicSmallString(SmallStringView{begin, end})
{}
explicit BasicSmallString(iterator begin, iterator end)
: BasicSmallString(SmallStringView{begin, end})
{}
template<typename Type, typename = std::enable_if_t<std::is_pointer<Type>::value>>
BasicSmallString(Type characterPointer)

View File

@@ -49,6 +49,7 @@ class SmallStringView
{
public:
using const_iterator = Internal::SmallStringIterator<std::random_access_iterator_tag, const char>;
using iterator = Internal::SmallStringIterator<std::random_access_iterator_tag, char>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using size_type = std::size_t;
@@ -62,14 +63,22 @@ public:
constexpr SmallStringView(const char *const string, const size_type size) noexcept
: m_pointer(string)
, m_size(size)
{
}
{}
constexpr SmallStringView(const const_iterator begin, const const_iterator end) noexcept
constexpr SmallStringView(const char *const begin, const char *const end) noexcept
: m_pointer(begin)
, m_size(static_cast<std::size_t>(std::distance(begin, end)))
{}
constexpr SmallStringView(const_iterator begin, const_iterator end) noexcept
: m_pointer(begin.data())
, m_size(std::size_t(end - begin))
{
}
{}
constexpr SmallStringView(iterator begin, 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

View File

@@ -39,6 +39,7 @@
#include <android/androidconstants.h>
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/reaper.h>
#include <cpptools/cppprojectupdater.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/generatedcodemodelsupport.h>
@@ -59,6 +60,7 @@
#include <utils/macroexpander.h>
#include <utils/mimetypes/mimetype.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <QClipboard>
#include <QDir>
@@ -207,6 +209,7 @@ CMakeBuildSystem::CMakeBuildSystem(CMakeBuildConfiguration *bc)
CMakeBuildSystem::~CMakeBuildSystem()
{
m_futureSynchronizer.waitForFinished();
if (!m_treeScanner.isFinished()) {
auto future = m_treeScanner.future();
future.cancel();
@@ -576,7 +579,7 @@ void CMakeBuildSystem::combineScanAndParse()
emitBuildSystemUpdated();
QTimer::singleShot(0, this, &CMakeBuildSystem::runCTest);
runCTest();
}
void CMakeBuildSystem::checkAndReportError(QString &errorMessage)
@@ -921,19 +924,38 @@ void CMakeBuildSystem::runCTest()
}
qCDebug(cmakeBuildSystemLog) << "Requesting ctest run after cmake run";
BuildDirParameters parameters(cmakeBuildConfiguration());
const BuildDirParameters parameters(cmakeBuildConfiguration());
QTC_ASSERT(parameters.isValid(), return);
FilePath workingDirectory = workDirectory(parameters);
CommandLine cmd{m_ctestPath, {"-N", "--show-only=json-v1"}};
SynchronousProcess ctest;
ctest.setTimeoutS(1);
ctest.setEnvironment(cmakeBuildConfiguration()->environment().toStringList());
ctest.setWorkingDirectory(workingDirectory.toString());
const CommandLine cmd { m_ctestPath, { "-N", "--show-only=json-v1" } };
const QString workingDirectory = workDirectory(parameters).toString();
const QStringList environment = cmakeBuildConfiguration()->environment().toStringList();
const SynchronousProcessResponse response = ctest.run(cmd);
if (response.result == SynchronousProcessResponse::Finished) {
const QJsonDocument json = QJsonDocument::fromJson(response.allRawOutput());
auto future = Utils::runAsync([cmd, workingDirectory, environment]
(QFutureInterface<QByteArray> &futureInterface) {
QProcess process;
process.setEnvironment(environment);
process.setWorkingDirectory(workingDirectory);
process.start(cmd.executable().toString(), cmd.splitArguments(), QIODevice::ReadOnly);
if (!process.waitForStarted(1000) || !process.waitForFinished(1000)) {
if (process.state() == QProcess::NotRunning)
return;
process.terminate();
if (process.waitForFinished(1000))
return;
process.kill();
process.waitForFinished(1000);
return;
}
if (process.exitCode() || process.exitStatus() != QProcess::NormalExit)
return;
futureInterface.reportResult(process.readAllStandardOutput());
});
Utils::onFinished(future, this, [this](const QFuture<QByteArray> &future) {
if (future.resultCount()) {
const QJsonDocument json = QJsonDocument::fromJson(future.result());
if (!json.isEmpty() && json.isObject()) {
const QJsonObject jsonObj = json.object();
const QJsonObject btGraph = jsonObj.value("backtraceGraph").toObject();
@@ -949,14 +971,15 @@ void CMakeBuildSystem::runCTest()
int file = btRef.value("file").toInt(-1);
int line = btRef.value("line").toInt(-1);
QTC_ASSERT(file != -1 && line != -1, continue);
m_testNames.append({test.value("name").toString(),
FilePath::fromString(cmakelists.at(file).toString()),
line
});
m_testNames.append({ test.value("name").toString(),
FilePath::fromString(cmakelists.at(file).toString()), line });
}
}
}
emit testInformationUpdated();
});
m_futureSynchronizer.addFuture(future);
}
CMakeBuildConfiguration *CMakeBuildSystem::cmakeBuildConfiguration() const

View File

@@ -35,6 +35,8 @@
#include <utils/fileutils.h>
#include <utils/temporarydirectory.h>
#include <QFutureSynchronizer>
namespace ProjectExplorer { class ExtraCompiler; }
namespace CppTools {
@@ -181,6 +183,7 @@ private:
// CTest integration
QString m_ctestPath;
QList<ProjectExplorer::TestCaseInfo> m_testNames;
QFutureSynchronizer<QByteArray> m_futureSynchronizer;
};
} // namespace Internal

View File

@@ -1147,26 +1147,6 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
return;
}
// Ignore signals from the process stub.
const GdbMi frame = data["frame"];
if (terminal()
&& data["reason"].data() == "signal-received"
&& data["signal-name"].data() == "SIGSTOP")
{
const QString from = frame["from"].data();
const QString func = frame["func"].data();
if (from.endsWith("/ld-linux.so.2")
|| from.endsWith("/ld-linux-x86-64.so.2")
|| func == "clone"
|| func == "kill")
{
showMessage("INTERNAL CONTINUE AFTER SIGSTOP FROM STUB", LogMisc);
notifyInferiorSpontaneousStop();
continueInferiorInternal();
return;
}
}
if (!m_onStop.isEmpty()) {
notifyInferiorStopOk();
showMessage("HANDLING QUEUED COMMANDS AFTER TEMPORARY STOP", LogMisc);
@@ -1184,6 +1164,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
QString fullName;
QString function;
QString language;
const GdbMi frame = data["frame"];
if (frame.isValid()) {
const GdbMi lineNumberG = frame["line"];
function = frame["function"].data(); // V4 protocol
@@ -4920,7 +4901,9 @@ void GdbEngine::handleStubAttached(const DebuggerResponse &response, qint64 main
notifyEngineRunAndInferiorStopOk();
continueInferiorInternal();
} else {
showMessage("INFERIOR ATTACHED AND RUNNING");
showMessage("INFERIOR ATTACHED");
QTC_ASSERT(terminal(), return);
terminal()->kickoffProcess();
//notifyEngineRunAndInferiorRunOk();
// Wait for the upcoming *stopped and handle it there.
}

View File

@@ -183,6 +183,11 @@ TerminalRunner::TerminalRunner(RunControl *runControl, const Runnable &stubRunna
this, [this] { reportDone(); });
}
void TerminalRunner::kickoffProcess()
{
m_stubProc.kickoffProcess();
}
void TerminalRunner::interruptProcess()
{
m_stubProc.interruptProcess();

View File

@@ -77,6 +77,7 @@ public:
qint64 applicationPid() const { return m_applicationPid; }
qint64 applicationMainThreadId() const { return m_applicationMainThreadId; }
void kickoffProcess();
void interruptProcess();
void setRunAsRoot(bool on);

View File

@@ -30,6 +30,7 @@ add_qtc_plugin(QmlDesigner
settingspage.cpp settingspage.h settingspage.ui
shortcutmanager.cpp shortcutmanager.h
designermcumanager.cpp designermcumanager.h
richtexteditordialog.cpp richtexteditordialog.h
EXPLICIT_MOC
components/propertyeditor/propertyeditorvalue.h
components/connectioneditor/connectionviewwidget.h

View File

@@ -47,6 +47,7 @@
#include <QStyleOptionGraphicsItem>
#include <QTimeLine>
#include <QGraphicsView>
#include <QtMath>
#include <cmath>
@@ -57,8 +58,8 @@ const int blockRadius = 18;
const int blockAdjust = 40;
const int startItemOffset = 96;
const qreal fontSize = 10; // points
const qreal zoomLevelLabel = 0.5; // Everything lower than that will hide all labels
const qreal labelFontSize = 10;
const qreal labelShowThreshold = 0.25; // Everything lower than that will hide all labels
const qreal defaultDpi = 96.0;
void drawIcon(QPainter *painter,
@@ -627,12 +628,68 @@ void FormEditorFlowItem::updateGeometry()
}
}
void FormEditorFlowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
FormEditorItem::paint(painter, option, widget);
if (!painter->isActive())
return;
if (!qmlItemNode().isValid())
return;
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
QPen pen;
pen.setJoinStyle(Qt::MiterJoin);
QColor flowColor(0xe71919);
if (qmlItemNode().rootModelNode().hasAuxiliaryData("areaColor"))
flowColor = qmlItemNode().rootModelNode().auxiliaryData("areaColor").value<QColor>();
if (qmlItemNode().modelNode().hasAuxiliaryData("color"))
flowColor = qmlItemNode().modelNode().auxiliaryData("color").value<QColor>();
pen.setColor(flowColor);
qreal width = 2;
// if (qmlItemNode().modelNode().hasAuxiliaryData("width"))
// width = qmlItemNode().modelNode().auxiliaryData("width").toInt();
width *= getLineScaleFactor();
pen.setWidthF(width);
bool dash = false;
if (qmlItemNode().modelNode().hasAuxiliaryData("dash"))
dash = qmlItemNode().modelNode().auxiliaryData("dash").toBool();
if (dash)
pen.setStyle(Qt::DashLine);
else
pen.setStyle(Qt::SolidLine);
pen.setCosmetic(false);
painter->setPen(pen);
QColor fillColor = QColor(Qt::transparent);
painter->setBrush(fillColor);
painter->drawRoundedRect(boundingRect(), blockRadius, blockRadius);
painter->restore();
}
QPointF FormEditorFlowItem::instancePosition() const
{
return qmlItemNode().flowPosition();
}
void FormEditorFlowActionItem::setDataModelPosition(const QPointF &position)
{
qmlItemNode().setPosition(position);
@@ -691,7 +748,6 @@ void FormEditorFlowActionItem::paint(QPainter *painter, const QStyleOptionGraphi
QPen pen;
pen.setJoinStyle(Qt::MiterJoin);
pen.setCosmetic(true);
QColor flowColor(0xe71919);
@@ -706,8 +762,9 @@ void FormEditorFlowActionItem::paint(QPainter *painter, const QStyleOptionGraphi
if (qmlItemNode().modelNode().hasAuxiliaryData("width"))
width = qmlItemNode().modelNode().auxiliaryData("width").toInt();
bool dash = false;
width *= getLineScaleFactor();
bool dash = false;
if (qmlItemNode().modelNode().hasAuxiliaryData("dash"))
dash = qmlItemNode().modelNode().auxiliaryData("dash").toBool();
@@ -719,7 +776,7 @@ void FormEditorFlowActionItem::paint(QPainter *painter, const QStyleOptionGraphi
pen.setStyle(Qt::SolidLine);
pen.setWidthF(width);
pen.setCosmetic(true);
pen.setCosmetic(false);
painter->setPen(pen);
QColor fillColor = QColor(Qt::transparent);
@@ -867,10 +924,8 @@ class ConnectionConfiguration
public:
ConnectionConfiguration(const QmlItemNode &node,
const ResolveConnection &resolveConnection,
const qreal scaleFactor,
bool hitTest = false)
: width(2)
, adjustedWidth(width / scaleFactor)
, color(QColor(0xe71919))
, lineBrush(QBrush(color))
, penStyle(Qt::SolidLine)
@@ -883,9 +938,10 @@ public:
, breakOffset(50)
, radius(8)
, bezier(50)
, fontSize(labelFontSize)
, type(ConnectionType::Default)
, label()
, labelOffset(14 / scaleFactor)
, labelOffset(14)
, labelPosition(50.0)
, labelFlags(Qt::AlignHCenter | Qt::AlignVCenter | Qt::TextDontClip)
, labelFlipSide(false)
@@ -895,12 +951,12 @@ public:
{
// width
if (node.modelNode().hasAuxiliaryData("width"))
width = node.modelNode().auxiliaryData("width").toInt();
width = node.modelNode().auxiliaryData("width").toFloat();
// adjusted width
if (node.modelNode().isSelected())
width += 2;
if (hitTest)
width = width * 8 / scaleFactor;
width = width * 8;
// color
if (resolveConnection.isStartLine)
color = QColor("blue");
@@ -966,7 +1022,6 @@ public:
}
qreal width;
qreal adjustedWidth;
QColor color; // TODO private/setter
QBrush lineBrush;
Qt::PenStyle penStyle;
@@ -980,6 +1035,7 @@ public:
int breakOffset;
int radius;
int bezier;
qreal fontSize;
ConnectionType type;
QString label;
qreal labelOffset;
@@ -1285,7 +1341,7 @@ public:
const bool boolExitRight = fromRect.right() < toRect.center().x();
const bool boolExitBottom = fromRect.bottom() < toRect.center().y();
const qreal padding = 8;
const int padding = 4 * config.width;
if (horizontalFirst) {
const qreal startX = boolExitRight ? fromRect.right() + padding : fromRect.x() - padding;
@@ -1405,7 +1461,7 @@ void FormEditorTransitionItem::updateGeometry()
QPixmap pixmap(640, 480);
QPainter localPainter(&pixmap);
QFont font = localPainter.font();
font.setPointSizeF(getFontSize(&localPainter) / getScaleFactor());
font.setPixelSize(labelFontSize * getTextScaleFactor());
localPainter.setFont(font);
const auto fromNodes = resolved.from;
@@ -1481,7 +1537,7 @@ void FormEditorTransitionItem::drawSingleLabel(QPainter *painter, const Connecti
QPointF position;
qreal angle;
const qreal hMargin = 10.0 / getScaleFactor();
const qreal hMargin = 10.0 * getItemScaleFactor();
QFontMetrics metric(painter->font());
const qreal lineHeight = metric.boundingRect("Xyz").height();
@@ -1506,7 +1562,7 @@ void FormEditorTransitionItem::drawSingleLabel(QPainter *painter, const Connecti
labelRect.adjust(-hMargin, 0.0, hMargin, 0.0);
if (singleEvent && singleSignal)
labelRect.setHeight(eventRect.height() + signalRect.height() + (6.0 / getScaleFactor()));
labelRect.setHeight(eventRect.height() + signalRect.height() + (6.0 * getTextScaleFactor()));
const qreal halfHeight = labelRect.height() * 0.5;
@@ -1526,7 +1582,7 @@ void FormEditorTransitionItem::drawSingleLabel(QPainter *painter, const Connecti
// Calculate font bounding box without taking into account the cale factor
QFont originalFont = painter->font();
originalFont.setPointSizeF(getFontSize(painter));
originalFont.setPixelSize(labelFontSize * getTextScaleFactor());
QFontMetrics originalMetric(originalFont);
QRectF originalTextRect = originalMetric.boundingRect(events);
originalTextRect.adjust(-10.0, 0.0, 10.0, 0.0);
@@ -1588,9 +1644,9 @@ void FormEditorTransitionItem::drawSingleLabel(QPainter *painter, const Connecti
painter->setPen(Qt::white);
if (singleEvent && singleSignal) {
eventRect.setWidth(labelRect.width());
eventRect.moveTopLeft(labelRect.topLeft() + QPointF(0.0, 4.0 / getScaleFactor()));
eventRect.moveTopLeft(labelRect.topLeft() + QPointF(0.0, 4.0 * getItemScaleFactor()));
signalRect.setWidth(labelRect.width());
signalRect.moveBottomLeft(labelRect.bottomLeft() - QPointF(0.0, 4.0 / getScaleFactor()));
signalRect.moveBottomLeft(labelRect.bottomLeft() - QPointF(0.0, 4.0 * getItemScaleFactor()));
painter->drawText(eventRect, Qt::AlignCenter, events);
painter->drawText(signalRect, Qt::AlignCenter, targetSignal);
@@ -1619,9 +1675,8 @@ void FormEditorTransitionItem::drawSelectionLabel(QPainter *painter, const Conne
const QStringList events = connection.config.events.split(',');
const int eventCount = events.size();
const qreal scaleFactor = getScaleFactor();
const qreal radius = 7.0 / scaleFactor;
const qreal hMargin = 10.0 / scaleFactor;
const qreal radius = 7.0 * getItemScaleFactor();
const qreal hMargin = 10.0 * getItemScaleFactor();
QFontMetrics metric(painter->font());
const qreal lineHeight = metric.boundingRect("Xyz").height();
@@ -1657,7 +1712,7 @@ void FormEditorTransitionItem::drawSelectionLabel(QPainter *painter, const Conne
}
const int signalCount = signalList.size();
const qreal offset = 10.0 / scaleFactor;
const qreal offset = 10.0 * getItemScaleFactor();
qreal totalHeight = 0;
if (hasEvents)
@@ -1730,34 +1785,33 @@ void FormEditorTransitionItem::drawSelectionLabel(QPainter *painter, const Conne
static void drawArrow(QPainter *painter,
const QPointF &point,
const qreal &angle,
const qreal &arrowLength,
const qreal &arrowWidth)
qreal arrowSize,
qreal arrowTipAngle = 90.0)
{
const QPointF peakP(0, 0);
const QPointF leftP(-arrowLength, -arrowWidth * 0.5);
const QPointF rightP(-arrowLength, arrowWidth * 0.5);
const QPointF endP(-arrowSize, 0);
painter->save();
painter->translate(point);
painter->rotate(-angle);
painter->drawLine(leftP, peakP);
painter->drawLine(rightP, peakP);
painter->rotate(-angle - (arrowTipAngle/2.0));
painter->drawLine(peakP, endP);
painter->rotate(arrowTipAngle);
painter->drawLine(peakP, endP);
painter->restore();
}
void FormEditorTransitionItem::paintConnection(QPainter *painter, const Connection &connection)
{
const qreal arrowLength = 4 * connection.config.adjustedWidth;
const qreal arrowWidth = 8 * connection.config.adjustedWidth;
const int arrowSize = 12 * getLineScaleFactor();
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
// Draw path/connection line
QPen pen;
pen.setCosmetic(true);
pen.setCosmetic(false);
pen.setJoinStyle(Qt::MiterJoin);
pen.setCapStyle(Qt::RoundCap);
pen.setBrush(connection.config.lineBrush);
@@ -1769,12 +1823,12 @@ void FormEditorTransitionItem::paintConnection(QPainter *painter, const Connecti
pen.setStyle(connection.config.penStyle);
}
pen.setWidthF(connection.config.width);
pen.setWidthF(connection.config.width * getLineScaleFactor());
painter->setPen(pen);
painter->drawPath(connection.path);
pen.setWidthF(connection.config.width);
pen.setWidthF(connection.config.width * getLineScaleFactor());
pen.setStyle(Qt::SolidLine);
pen.setColor(connection.config.color);
painter->setPen(pen);
@@ -1791,16 +1845,16 @@ void FormEditorTransitionItem::paintConnection(QPainter *painter, const Connecti
}
if (connection.config.drawEnd)
drawArrow(painter, connection.end, angle, arrowLength, arrowWidth);
drawArrow(painter, connection.end, angle, arrowSize, 60.0);
// Draw start ellipse
if (connection.config.drawStart) {
painter->setBrush(Qt::white);
painter->drawEllipse(connection.start, arrowLength / 2.0, arrowLength / 2.0);
painter->drawEllipse(connection.start, arrowSize / 5, arrowSize / 5);
}
// Draw labels
if (viewportTransform().m11() >= zoomLevelLabel)
if (viewportTransform().m11() >= labelShowThreshold)
drawLabels(painter, connection);
painter->restore();
@@ -1825,11 +1879,11 @@ void FormEditorTransitionItem::paint(QPainter *painter, const QStyleOptionGraphi
if (!isModelNodeValid(resolved.from))
return;
ConnectionConfiguration config(qmlItemNode(), resolved, viewportTransform().m11(), m_hitTest);
ConnectionConfiguration config(qmlItemNode(), resolved, m_hitTest);
QFont f = painter->font();
f.setPointSizeF(getFontSize(painter) / getScaleFactor());
painter->setFont(f);
QFont font = painter->font();
font.setPixelSize(config.fontSize * getTextScaleFactor());
painter->setFont(font);
const auto fromNodes = resolved.from;
const auto toNodes = resolved.to;
@@ -1896,7 +1950,7 @@ void FormEditorTransitionItem::paint(QPainter *painter, const QStyleOptionGraphi
const QString icon = Theme::getIconUnicode(Theme::startNode);
QPen pen;
pen.setCosmetic(true);
pen.setCosmetic(false);
pen.setColor(config.color);
painter->setPen(pen);
@@ -1937,18 +1991,19 @@ QTransform FormEditorItem::viewportTransform() const
return scene()->views().first()->viewportTransform();
}
qreal FormEditorItem::getFontSize(QPainter *painter) const
qreal FormEditorItem::getItemScaleFactor() const
{
const int dpi = std::max(painter->device()->logicalDpiX(),
painter->device()->logicalDpiY());
return fontSize * (dpi / defaultDpi);
return 1.0 / viewportTransform().m11();
}
qreal FormEditorItem::getScaleFactor() const
qreal FormEditorItem::getLineScaleFactor() const
{
// Cap scaling at 100% zoom
return (viewportTransform().m11() >= 1.0) ? viewportTransform().m11() : 1.0;
return 2 / qSqrt(viewportTransform().m11());
}
qreal FormEditorItem::getTextScaleFactor() const
{
return 2 / qSqrt(viewportTransform().m11());
}
void FormEditorFlowDecisionItem::updateGeometry()
@@ -1960,6 +2015,7 @@ void FormEditorFlowDecisionItem::updateGeometry()
size = qmlItemNode().modelNode().auxiliaryData("blockSize").toInt();
QRectF boundingRect(0, 0, size, size);
QRectF selectionRect = boundingRect;
QTransform transform;
if (qmlItemNode().isFlowDecision()) {
transform.translate(boundingRect.center().x(), boundingRect.center().y());
@@ -1982,7 +2038,7 @@ void FormEditorFlowDecisionItem::updateGeometry()
QPixmap pixmap(640, 480);
QPainter localPainter(&pixmap);
QFont font = localPainter.font();
font.setPointSizeF(getFontSize(&localPainter) / getScaleFactor());
font.setPixelSize(labelFontSize * getTextScaleFactor());
localPainter.setFont(font);
const qreal margin = blockAdjust * 0.5;
@@ -2018,14 +2074,15 @@ void FormEditorFlowDecisionItem::updateGeometry()
}
}
// Unite the rotate item bounding rect with the label bounding rect.
// bounding rect is combination of label and icon but only icon can be clicked
boundingRect = transform.mapRect(boundingRect);
selectionRect = boundingRect;
boundingRect = boundingRect.united(labelBoundingRect);
}
m_selectionBoundingRect = boundingRect;
m_paintedBoundingRect = m_selectionBoundingRect;
m_boundingRect = m_paintedBoundingRect;
m_selectionBoundingRect = selectionRect;
m_boundingRect = boundingRect;
m_paintedBoundingRect = boundingRect;
setTransform(qmlItemNode().instanceTransformWithContentTransform());
const QPointF pos = qmlItemNode().flowPosition();
setTransform(QTransform::fromTranslate(pos.x(), pos.y()));
@@ -2045,7 +2102,7 @@ void FormEditorFlowDecisionItem::paint(QPainter *painter, const QStyleOptionGrap
QPen pen;
pen.setJoinStyle(Qt::MiterJoin);
pen.setCosmetic(true);
pen.setCosmetic(false);
QColor flowColor(0xe71919);
@@ -2055,24 +2112,26 @@ void FormEditorFlowDecisionItem::paint(QPainter *painter, const QStyleOptionGrap
if (qmlItemNode().modelNode().hasAuxiliaryData("color"))
flowColor = qmlItemNode().modelNode().auxiliaryData("color").value<QColor>();
pen.setColor(flowColor);
qreal width = 2;
if (qmlItemNode().modelNode().hasAuxiliaryData("width"))
width = qmlItemNode().modelNode().auxiliaryData("width").toInt();
width *= getLineScaleFactor();
pen.setWidthF(width);
bool dash = false;
if (qmlItemNode().modelNode().hasAuxiliaryData("dash"))
dash = qmlItemNode().modelNode().auxiliaryData("dash").toBool();
pen.setColor(flowColor);
if (dash)
pen.setStyle(Qt::DashLine);
else
pen.setStyle(Qt::SolidLine);
pen.setWidthF(width);
pen.setCosmetic(true);
painter->setPen(pen);
QColor fillColor = QColor(Qt::transparent);
@@ -2119,7 +2178,7 @@ void FormEditorFlowDecisionItem::paint(QPainter *painter, const QStyleOptionGrap
if (qmlItemNode().modelNode().hasAuxiliaryData("showDialogLabel"))
showDialogLabel = qmlItemNode().modelNode().auxiliaryData("showDialogLabel").toBool();
if (showDialogLabel && viewportTransform().m11() >= zoomLevelLabel) {
if (showDialogLabel && viewportTransform().m11() >= labelShowThreshold) {
QString dialogTitle;
if (qmlItemNode().modelNode().hasVariantProperty("dialogTitle"))
dialogTitle = qmlItemNode().modelNode().variantProperty("dialogTitle").value().toString();
@@ -2127,7 +2186,7 @@ void FormEditorFlowDecisionItem::paint(QPainter *painter, const QStyleOptionGrap
if (!dialogTitle.isEmpty()) {
QFont font = painter->font();
font.setPointSizeF(getFontSize(painter) / getScaleFactor());
font.setPixelSize(labelFontSize * getTextScaleFactor());
painter->setFont(font);
QRectF textRect(0, 0, 100, 20);

View File

@@ -128,8 +128,10 @@ protected:
QList<FormEditorItem*> offspringFormEditorItemsRecursive(const FormEditorItem *formEditorItem) const;
FormEditorItem(const QmlItemNode &qmlItemNode, FormEditorScene* scene);
QTransform viewportTransform() const;
qreal getFontSize(QPainter *painter) const;
qreal getScaleFactor() const;
qreal getItemScaleFactor() const;
qreal getLineScaleFactor() const;
qreal getTextScaleFactor() const;
QRectF m_boundingRect;
QRectF m_paintedBoundingRect;
@@ -161,6 +163,7 @@ public:
void setDataModelPositionInBaseState(const QPointF &position) override;
void updateGeometry() override;
QPointF instancePosition() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
protected:
FormEditorFlowItem(const QmlItemNode &qmlItemNode, FormEditorScene *scene)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 B

View File

@@ -29,17 +29,7 @@
<file>images/asset_sound_192.png</file>
<file>images/asset_sound_256.png</file>
<file>images/asset_sound_384.png</file>
<file>images/tab_icon.png</file>
<file>images/tab_icon@2x.png</file>
<file>images/x.png</file>
<file>images/x@2x.png</file>
<file>images/add.png</file>
<file>images/add@2x.png</file>
<file>images/add_unselected.png</file>
<file>images/add_unselected@2x.png</file>
<file>images/down.png</file>
<file>images/down@2x.png</file>
<file>qml/libraryheader.qml</file>
<file>qml/addimport.qml</file>
</qresource>
</RCC>

View File

@@ -102,6 +102,7 @@ void ItemLibraryCategoriesModel::expandCategories(bool expand)
for (const auto &category : std::as_const(m_categoryList)) {
if (category->categoryExpanded() != expand) {
category->setExpanded(expand);
ItemLibraryModel::saveExpandedState(expand, category->categoryName());
emit dataChanged(index(i), index(i), {m_roleNames.key("categoryExpanded")});
}
++i;

View File

@@ -60,7 +60,7 @@ QObject *ItemLibraryCategory::itemModel()
return &m_itemModel;
}
bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool *changed)
bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool *changed, bool expand)
{
bool hasVisibleItems = false;
@@ -81,7 +81,7 @@ bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool *
}
// expand category if it has an item matching search criteria
if (hasVisibleItems && !categoryExpanded())
if (expand && hasVisibleItems && !categoryExpanded())
setExpanded(true);
return hasVisibleItems;

View File

@@ -50,7 +50,7 @@ public:
void addItem(ItemLibraryItem *item);
QObject *itemModel();
bool updateItemVisibility(const QString &searchText, bool *changed);
bool updateItemVisibility(const QString &searchText, bool *changed, bool expand = false);
bool setVisible(bool isVisible);
bool isVisible() const;

View File

@@ -95,14 +95,14 @@ void ItemLibraryImport::expandCategories(bool expand)
m_categoryModel.expandCategories(expand);
}
bool ItemLibraryImport::updateCategoryVisibility(const QString &searchText, bool *changed)
bool ItemLibraryImport::updateCategoryVisibility(const QString &searchText, bool *changed, bool expand)
{
bool hasVisibleCategories = false;
*changed = false;
for (const auto &category : m_categoryModel.categorySections()) {
bool categoryChanged = false;
bool hasVisibleItems = category->updateItemVisibility(searchText, &categoryChanged);
bool hasVisibleItems = category->updateItemVisibility(searchText, &categoryChanged, expand);
categoryChanged |= category->setVisible(hasVisibleItems);
*changed |= categoryChanged;

View File

@@ -67,7 +67,7 @@ public:
void addCategory(ItemLibraryCategory *category);
QObject *categoryModel();
bool updateCategoryVisibility(const QString &searchText, bool *changed);
bool updateCategoryVisibility(const QString &searchText, bool *changed, bool expand = false);
bool setVisible(bool isVisible);
void setImportUsed(bool importUsed);
void sortCategorySections();

View File

@@ -163,7 +163,7 @@ void ItemLibraryModel::setSearchText(const QString &searchText)
m_searchText = lowerSearchText;
bool changed = false;
updateVisibility(&changed);
updateVisibility(&changed, !m_searchText.isEmpty());
}
}
@@ -374,18 +374,18 @@ void ItemLibraryModel::updateUsedImports(const QList<Import> &usedImports)
}
}
void ItemLibraryModel::updateVisibility(bool *changed)
void ItemLibraryModel::updateVisibility(bool *changed, bool expand)
{
for (ItemLibraryImport *import : std::as_const(m_importList)) {
bool categoryChanged = false;
bool hasVisibleItems = import->updateCategoryVisibility(m_searchText, &categoryChanged);
bool hasVisibleItems = import->updateCategoryVisibility(m_searchText, &categoryChanged, expand);
*changed |= categoryChanged;
if (import->sectionType() == ItemLibraryImport::SectionType::Unimported)
*changed |= import->setVisible(!m_searchText.isEmpty());
// expand import if it has an item matching search criteria
if (hasVisibleItems && !import->importExpanded())
if (expand && hasVisibleItems && !import->importExpanded())
import->setImportExpanded();
}

View File

@@ -72,7 +72,7 @@ public:
Import entryToImport(const ItemLibraryEntry &entry);
private:
void updateVisibility(bool *changed);
void updateVisibility(bool *changed, bool expand = false);
void addRoleNames();
void sortSections();
void clearSections();

View File

@@ -141,27 +141,19 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
// create header widget
m_headerWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_headerWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
Theme::setupTheme(m_headerWidget->engine());
m_headerWidget->setSource(QUrl("qrc:/ItemLibrary/qml/libraryheader.qml"));
QObject::connect(m_headerWidget->rootObject(), SIGNAL(tabChanged(int)), this,
SLOT(handleTabChanged(int)));
QObject::connect(m_headerWidget->rootObject(), SIGNAL(filterChanged(QString)), this,
SLOT(handleFilterChanged(QString)));
QObject::connect(m_headerWidget->rootObject(), SIGNAL(addModuleClicked()), this,
SLOT(handleAddModule()));
QObject::connect(m_headerWidget->rootObject(), SIGNAL(addAssetClicked()), this,
SLOT(handleAddAsset()));
m_headerWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_headerWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
m_headerWidget->rootContext()->setContextProperty("rootView", QVariant::fromValue(this));
// create add imports widget
m_addImportWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_addImportWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
Theme::setupTheme(m_addImportWidget->engine());
m_addImportWidget->setSource(QUrl("qrc:/ItemLibrary/qml/addimport.qml"));
m_addImportWidget->rootContext()->setContextProperty(
"addImportModel", QVariant::fromValue(m_itemLibraryAddImportModel.data()));
QObject::connect(m_addImportWidget->rootObject(), SIGNAL(addImport(int)), this,
SLOT(handleAddImport(int)));
m_addImportWidget->rootContext()->setContextProperties({
{"addImportModel", QVariant::fromValue(m_itemLibraryAddImportModel.data())},
{"rootView", QVariant::fromValue(this)},
});
// set up Item Library view and model
m_itemViewQuickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
@@ -270,7 +262,7 @@ QList<QToolButton *> ItemLibraryWidget::createToolBarWidgets()
return buttons;
}
void ItemLibraryWidget::handleFilterChanged(const QString &filterText)
void ItemLibraryWidget::handleSearchfilterChanged(const QString &filterText)
{
m_filterText = filterText;
@@ -339,11 +331,20 @@ void ItemLibraryWidget::clearSearchFilter()
void ItemLibraryWidget::reloadQmlSource()
{
QString itemLibraryQmlFilePath = qmlSourcesPath() + QStringLiteral("/ItemsView.qml");
const QString libraryHeaderQmlPath = qmlSourcesPath() + "/LibraryHeader.qml";
QTC_ASSERT(QFileInfo::exists(libraryHeaderQmlPath), return);
m_headerWidget->engine()->clearComponentCache();
m_headerWidget->setSource(QUrl::fromLocalFile(libraryHeaderQmlPath));
QTC_ASSERT(QFileInfo::exists(itemLibraryQmlFilePath), return);
const QString addImportQmlPath = qmlSourcesPath() + "/AddImport.qml";
QTC_ASSERT(QFileInfo::exists(addImportQmlPath), return);
m_addImportWidget->engine()->clearComponentCache();
m_addImportWidget->setSource(QUrl::fromLocalFile(addImportQmlPath));
const QString itemLibraryQmlPath = qmlSourcesPath() + "/ItemsView.qml";
QTC_ASSERT(QFileInfo::exists(itemLibraryQmlPath), return);
m_itemViewQuickWidget->engine()->clearComponentCache();
m_itemViewQuickWidget->setSource(QUrl::fromLocalFile(itemLibraryQmlFilePath));
m_itemViewQuickWidget->setSource(QUrl::fromLocalFile(itemLibraryQmlPath));
}
void ItemLibraryWidget::updateModel()

View File

@@ -91,6 +91,11 @@ public:
Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos);
Q_INVOKABLE void removeImport(const QString &importUrl);
Q_INVOKABLE void addImportForItem(const QVariant &entry);
Q_INVOKABLE void handleTabChanged(int index);
Q_INVOKABLE void handleAddModule();
Q_INVOKABLE void handleAddAsset();
Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText);
Q_INVOKABLE void handleAddImport(int index);
signals:
void itemActivated(const QString& itemName);
@@ -130,13 +135,6 @@ private:
bool m_updateRetry = false;
QString m_filterText;
QPoint m_dragStartPoint;
private slots:
void handleTabChanged(int index);
void handleFilterChanged(const QString &filterText);
void handleAddModule();
void handleAddAsset();
void handleAddImport(int index);
};
}
} // namespace QmlDesigner

View File

@@ -132,6 +132,8 @@ RichTextEditor::RichTextEditor(QWidget *parent)
this, &RichTextEditor::currentCharFormatChanged);
connect(ui->textEdit, &QTextEdit::cursorPositionChanged,
this, &RichTextEditor::cursorPositionChanged);
connect(ui->textEdit, &QTextEdit::textChanged,
this, &RichTextEditor::onTextChanged);
connect(m_linkDialog, &QDialog::accepted, [this]() {
QTextCharFormat oldFormat = ui->textEdit->textCursor().charFormat();
@@ -223,6 +225,10 @@ void RichTextEditor::cursorPositionChanged()
tableChanged(ui->textEdit->textCursor());
}
void RichTextEditor::onTextChanged() {
emit textChanged(richText());
}
void RichTextEditor::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
{
QTextCursor cursor = ui->textEdit->textCursor();

View File

@@ -69,11 +69,12 @@ public:
signals:
void insertingImage(QString &filePath);
void textChanged(QString text);
private slots:
void currentCharFormatChanged(const QTextCharFormat &format);
void cursorPositionChanged();
void onTextChanged();
private:
QIcon getIcon(Theme::Icon icon);
void mergeFormatOnWordOrSelection(const QTextCharFormat &format);

View File

@@ -76,6 +76,9 @@ void TextEditItem::setFormEditorItem(FormEditorItem *formEditorItem)
QSize maximumSize = rect.size().toSize();
activateTextEdit(maximumSize);
} else {
auto lineEdit = TextEditItemWidget::lineEdit();
auto node = m_formEditorItem->qmlItemNode();
lineEdit->setFont(node.instanceValue("font").value<QFont>());
activateLineEdit();
}

View File

@@ -36,6 +36,7 @@
#include "nodemetainfo.h"
#include "qmlitemnode.h"
#include "richtexteditordialog.h"
#include <qmldesignerplugin.h>
#include <abstractaction.h>
@@ -207,6 +208,14 @@ void TextTool::selectedItemsChanged(const QList<FormEditorItem*> &itemList)
}
if (!itemList.isEmpty()) {
FormEditorItem *formEditorItem = itemList.constFirst();
auto text = formEditorItem->qmlItemNode().instanceValue("text").toString();
auto format = formEditorItem->qmlItemNode().instanceValue("format").value<int>();
if (format == Qt::RichText || Qt::mightBeRichText(text)) {
RichTextEditorDialog* editorDialog = new RichTextEditorDialog(text);
editorDialog->setFormEditorItem(formEditorItem);
editorDialog->show();
view()->changeToSelectionTool();
} else {
m_textItem = new TextEditItem(scene());
textItem()->setParentItem(scene()->manipulatorLayerItem());
textItem()->setFormEditorItem(formEditorItem);
@@ -214,6 +223,7 @@ void TextTool::selectedItemsChanged(const QList<FormEditorItem*> &itemList)
textItem()->writeTextToProperty();
view()->changeToSelectionTool();
});
}
} else {
view()->changeToSelectionTool();
}

View File

@@ -205,6 +205,7 @@ public:
virtual void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList);
virtual void propertiesRemoved(const QList<AbstractProperty>& propertyList);
virtual void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange);
virtual void bindingPropertiesAboutToBeChanged(const QList<BindingProperty> &propertyList);
virtual void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange);
virtual void signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty>& propertyList, PropertyChangeFlags propertyChange);
virtual void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion);

View File

@@ -94,7 +94,7 @@ public:
static bool sameContent(const Comment &a, const Comment &b);
bool operator==(const Comment &comment) const; //everything is similar.
bool isEmpty();
bool isEmpty() const;
QString toQString() const;

View File

@@ -47,6 +47,7 @@
#include <qmlprojectmanager/qmlmultilanguageaspect.h>
#include <qmlprojectmanager/qmlproject.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtsupportconstants.h>
@@ -167,6 +168,20 @@ QString PuppetCreator::getStyleConfigFileName() const
return QString();
}
bool PuppetCreator::usesVirtualKeyboard() const
{
#ifndef QMLDESIGNER_TEST
if (m_target) {
auto *qmlbuild = qobject_cast<QmlProjectManager::QmlBuildSystem *>(m_target->buildSystem());
const Utils::EnvironmentItem virtualKeyboard("QT_IM_MODULE", "qtvirtualkeyboard");
return qmlbuild && qmlbuild->environment().indexOf(virtualKeyboard);
}
#endif
return false;
}
PuppetCreator::PuppetCreator(ProjectExplorer::Target *target, const Model *model)
: m_target(target)
@@ -494,6 +509,11 @@ QProcessEnvironment PuppetCreator::processEnvironment() const
environment.set("QMLDESIGNER_RC_PATHS", m_qrcMapping);
}
if (usesVirtualKeyboard()) {
environment.set("QT_IM_MODULE", "qtvirtualkeyboard");
environment.set("QT_VIRTUALKEYBOARD_DESKTOP_DISABLE", "1");
}
#ifndef QMLDESIGNER_TEST
// set env var if QtQuick3D import exists
QmlDesigner::Import import = QmlDesigner::Import::createLibraryImport("QtQuick3D", "1.0");

View File

@@ -103,6 +103,7 @@ protected:
bool useOnlyFallbackPuppet() const;
QString getStyleConfigFileName() const;
bool usesVirtualKeyboard() const;
private:
mutable QString m_compileLog;

View File

@@ -329,6 +329,8 @@ void AbstractView::variantPropertiesChanged(const QList<VariantProperty>& /*prop
{
}
void AbstractView::bindingPropertiesAboutToBeChanged(const QList<BindingProperty> &) {}
void AbstractView::bindingPropertiesChanged(const QList<BindingProperty>& /*propertyList*/, PropertyChangeFlags /*propertyChange*/)
{
}

View File

@@ -133,7 +133,7 @@ bool Comment::operator==(const Comment &comment) const
return (sameContent(comment) && (m_timestamp == comment.timestamp()));
}
bool Comment::isEmpty()
bool Comment::isEmpty() const
{
return sameContent(Comment());
}

View File

@@ -767,6 +767,21 @@ void ModelPrivate::notifyNodeIdChanged(const InternalNodePointer &node,
});
}
void ModelPrivate::notifyBindingPropertiesAboutToBeChanged(
const QList<InternalBindingPropertyPointer> &internalPropertyList)
{
notifyNodeInstanceViewLast([&](AbstractView *view) {
QList<BindingProperty> propertyList;
for (const InternalBindingPropertyPointer &bindingProperty : internalPropertyList) {
propertyList.append(BindingProperty(bindingProperty->name(),
bindingProperty->propertyOwner(),
m_model,
view));
}
view->bindingPropertiesAboutToBeChanged(propertyList);
});
}
void ModelPrivate::notifyBindingPropertiesChanged(
const QList<InternalBindingPropertyPointer> &internalPropertyList,
AbstractView::PropertyChangeFlags propertyChange)
@@ -1030,6 +1045,7 @@ void ModelPrivate::setBindingProperty(const InternalNodePointer &node, const Pro
}
InternalBindingPropertyPointer bindingProperty = node->bindingProperty(name);
notifyBindingPropertiesAboutToBeChanged({bindingProperty});
bindingProperty->setExpression(expression);
notifyBindingPropertiesChanged({bindingProperty}, propertyChange);
}
@@ -1087,6 +1103,7 @@ void ModelPrivate::setDynamicBindingProperty(const InternalNodePointer &node,
}
InternalBindingPropertyPointer bindingProperty = node->bindingProperty(name);
notifyBindingPropertiesAboutToBeChanged({bindingProperty});
bindingProperty->setDynamicExpression(dynamicPropertyType, expression);
notifyBindingPropertiesChanged({bindingProperty}, propertyChange);
}

View File

@@ -149,6 +149,8 @@ public:
void notifyPropertiesRemoved(const QList<PropertyPair> &propertyList);
void notifyPropertiesAboutToBeRemoved(const QList<InternalPropertyPointer> &internalPropertyList);
void notifyBindingPropertiesAboutToBeChanged(
const QList<InternalBindingPropertyPointer> &internalPropertyList);
void notifyBindingPropertiesChanged(const QList<InternalBindingPropertyPointer> &internalPropertyList, AbstractView::PropertyChangeFlags propertyChange);
void notifySignalHandlerPropertiesChanged(const QVector<InternalSignalHandlerPropertyPointer> &propertyList, AbstractView::PropertyChangeFlags propertyChange);
void notifyVariantPropertiesChanged(const InternalNodePointer &node, const PropertyNameList &propertyNameList, AbstractView::PropertyChangeFlags propertyChange);

View File

@@ -10,7 +10,8 @@ HEADERS += $$PWD/qmldesignerconstants.h \
$$PWD/documentwarningwidget.h \
$$PWD/qmldesignericons.h \
$$PWD/openuiqmlfiledialog.h \
$$PWD/designermcumanager.h
$$PWD/designermcumanager.h \
$$PWD/richtexteditordialog.h
SOURCES += $$PWD/qmldesignerplugin.cpp \
$$PWD/shortcutmanager.cpp \
@@ -22,7 +23,8 @@ SOURCES += $$PWD/qmldesignerplugin.cpp \
$$PWD/documentmanager.cpp \
$$PWD/documentwarningwidget.cpp \
$$PWD/openuiqmlfiledialog.cpp \
$$PWD/designermcumanager.cpp
$$PWD/designermcumanager.cpp \
$$PWD/richtexteditordialog.cpp
FORMS += $$PWD/settingspage.ui \
$$PWD/openuiqmlfiledialog.ui

View File

@@ -984,6 +984,8 @@ Project {
"shortcutmanager.h",
"designermcumanager.cpp",
"designermcumanager.h",
"richtexteditordialog.cpp",
"richtexteditordialog.h",
]
}
}

View File

@@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2021 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 "richtexteditordialog.h"
#include <QVBoxLayout>
namespace QmlDesigner {
RichTextEditorDialog::RichTextEditorDialog(QString text)
{
m_editor = new RichTextEditor(this);
m_editor->setRichText(text);
auto layout = new QVBoxLayout(this);
layout->addWidget(m_editor);
setLayout(layout);
connect(m_editor, &RichTextEditor::textChanged,
this, &RichTextEditorDialog::onTextChanged);
connect(this, &QDialog::finished,
this, &RichTextEditorDialog::onFinished);
setModal(true);
}
void RichTextEditorDialog::setFormEditorItem(FormEditorItem* formEditorItem)
{
m_formEditorItem = formEditorItem;
}
void RichTextEditorDialog::onTextChanged(QString text)
{
Q_UNUSED(text);
// TODO: try adding following and make it react faster
// setTextToFormEditorItem(text);
}
void RichTextEditorDialog::onFinished()
{
setTextToFormEditorItem(m_editor->richText());
}
void RichTextEditorDialog::setTextToFormEditorItem(QString text)
{
if (m_formEditorItem) {
if (text.isEmpty())
m_formEditorItem->qmlItemNode().removeProperty("text");
else
m_formEditorItem->qmlItemNode().setVariantProperty("text", text);
}
}
} //namespace QmlDesigner

View File

@@ -0,0 +1,56 @@
/****************************************************************************
**
** Copyright (C) 2021 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.
**
****************************************************************************/
#ifndef RICHTEXTEDITORDIALOG_H
#define RICHTEXTEDITORDIALOG_H
#include <QDialog>
#include "richtexteditor/richtexteditor.h"
#include "formeditor/formeditoritem.h"
namespace QmlDesigner {
class RichTextEditorDialog : public QDialog {
Q_OBJECT
public:
explicit RichTextEditorDialog(const QString text);
void setFormEditorItem(FormEditorItem* formEditorItem);
signals:
void textChanged(QString text);
private:
RichTextEditor* m_editor;
FormEditorItem* m_formEditorItem;
private slots:
void onTextChanged(QString text);
void onFinished();
void setTextToFormEditorItem(QString text);
};
} // namespace QmlDesigner
#endif // RICHTEXTEDITORDIALOG_H

View File

@@ -47,7 +47,7 @@ static Utils::FilePath getMultilanguageDatabaseFilePath(ProjectExplorer::Target
{
if (target) {
auto filePath = target->project()->projectDirectory().pathAppended(
"multilanguage-experimental-v3.db");
"multilanguage-experimental-v4.db");
if (filePath.exists())
return filePath;
}