diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index e1e0222d02b..651719dfffb 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -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 diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/addimport.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddImport.qml similarity index 97% rename from src/plugins/qmldesigner/components/itemlibrary/qml/addimport.qml rename to share/qtcreator/qmldesigner/itemLibraryQmlSources/AddImport.qml index e73623bd7ee..53712827700 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/qml/addimport.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddImport.qml @@ -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 } } diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml index a93bc173a81..2923451de50 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml @@ -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 diff --git a/src/plugins/qmldesigner/components/itemlibrary/qml/libraryheader.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml similarity index 62% rename from src/plugins/qmldesigner/components/itemlibrary/qml/libraryheader.qml rename to share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml index 18587c07ff4..da2e18ff873 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/qml/libraryheader.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml @@ -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 - text: modelData.title - font.pixelSize: 13 - font.bold: true - color: tabBar.currentIndex === index ? "#0094ce" : "#dadada" - anchors.bottomMargin: 2 - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignBottom - elide: Text.ElideRight - } + topPadding: 4 + bottomPadding: 4 + contentItem: Item { + implicitHeight: plusButton.height - background: Item { // TabButton background - Rectangle { // + button - anchors.right: parent.right + 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.rightMargin: 2 + anchors.right: plusButton.left anchors.bottomMargin: 2 - width: img.width + 10 - height: img.height + 10 + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignBottom + elide: Text.ElideRight + } + + Rectangle { // + button + id: plusButton + anchors.right: parent.right + 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 = "" } diff --git a/src/libs/sqlite/sqlitebasestatement.cpp b/src/libs/sqlite/sqlitebasestatement.cpp index cd6e2f0bb21..7412473dad1 100644 --- a/src/libs/sqlite/sqlitebasestatement.cpp +++ b/src/libs/sqlite/sqlitebasestatement.cpp @@ -716,7 +716,7 @@ StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column) break; } - return StringType{"", 0}; + return {}; } } // namespace diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h index c6baaaf4b92..c6052e20187 100644 --- a/src/libs/sqlite/sqlitebasestatement.h +++ b/src/libs/sqlite/sqlitebasestatement.h @@ -349,7 +349,7 @@ public: bindValues(queryValues...); while (BaseStatement::next()) - pushBackToContainer(container); + emplaceBackValues(container); resetter.reset(); } @@ -448,19 +448,6 @@ private: return callCallable(callable, std::make_integer_sequence{}); } - template - void pushBackToContainer(Container &container, std::integer_sequence) - { - using Type = typename Container::value_type; - container.push_back(Type(ValueGetter(*this, ColumnIndices)...)); - } - - template - void pushBackToContainer(Container &container) - { - pushBackToContainer(container, std::make_integer_sequence{}); - } - template void bindValuesByIndex(int index, const ValueType &value) { diff --git a/src/libs/utils/consoleprocess.cpp b/src/libs/utils/consoleprocess.cpp index bd6f6231b8c..18f6a73e6da 100644 --- a/src/libs/utils/consoleprocess.cpp +++ b/src/libs/utils/consoleprocess.cpp @@ -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 diff --git a/src/libs/utils/consoleprocess.h b/src/libs/utils/consoleprocess.h index ce53e0d87c7..16373fe76e0 100644 --- a/src/libs/utils/consoleprocess.h +++ b/src/libs/utils/consoleprocess.h @@ -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(); diff --git a/src/libs/utils/process_stub_unix.c b/src/libs/utils/process_stub_unix.c index 271404fe3bb..d7a7ff15b09 100644 --- a/src/libs/utils/process_stub_unix.c +++ b/src/libs/utils/process_stub_unix.c @@ -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; diff --git a/src/libs/utils/smallstring.h b/src/libs/utils/smallstring.h index 20d4a13e811..b04a2300a37 100644 --- a/src/libs/utils/smallstring.h +++ b/src/libs/utils/smallstring.h @@ -64,8 +64,8 @@ template class BasicSmallString { public: - using iterator = Internal::SmallStringIterator; - using const_iterator = Internal::SmallStringIterator; + using iterator = SmallStringView::iterator; + using const_iterator = SmallStringView::const_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_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::value>> BasicSmallString(Type characterPointer) diff --git a/src/libs/utils/smallstringview.h b/src/libs/utils/smallstringview.h index 5559d222322..6d3ea5d35fe 100644 --- a/src/libs/utils/smallstringview.h +++ b/src/libs/utils/smallstringview.h @@ -49,6 +49,7 @@ class SmallStringView { public: using const_iterator = Internal::SmallStringIterator; + using iterator = Internal::SmallStringIterator; using const_reverse_iterator = std::reverse_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::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 = 0> constexpr SmallStringView(const String &string) noexcept diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index ec843295ebd..73c21babb9e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ #include #include #include +#include #include #include @@ -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,42 +924,62 @@ 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()); - if (!json.isEmpty() && json.isObject()) { - const QJsonObject jsonObj = json.object(); - const QJsonObject btGraph = jsonObj.value("backtraceGraph").toObject(); - const QJsonArray cmakelists = btGraph.value("files").toArray(); - const QJsonArray nodes = btGraph.value("nodes").toArray(); - const QJsonArray tests = jsonObj.value("tests").toArray(); - for (const QJsonValue &testVal : tests) { - const QJsonObject test = testVal.toObject(); - QTC_ASSERT(!test.isEmpty(), continue); - const int bt = test.value("backtrace").toInt(-1); - QTC_ASSERT(bt != -1, continue); - const QJsonObject btRef = nodes.at(bt).toObject(); - 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 - }); + auto future = Utils::runAsync([cmd, workingDirectory, environment] + (QFutureInterface &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 &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(); + const QJsonArray cmakelists = btGraph.value("files").toArray(); + const QJsonArray nodes = btGraph.value("nodes").toArray(); + const QJsonArray tests = jsonObj.value("tests").toArray(); + for (const QJsonValue &testVal : tests) { + const QJsonObject test = testVal.toObject(); + QTC_ASSERT(!test.isEmpty(), continue); + const int bt = test.value("backtrace").toInt(-1); + QTC_ASSERT(bt != -1, continue); + const QJsonObject btRef = nodes.at(bt).toObject(); + 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 }); + } } } - } - emit testInformationUpdated(); + emit testInformationUpdated(); + }); + + m_futureSynchronizer.addFuture(future); } CMakeBuildConfiguration *CMakeBuildSystem::cmakeBuildConfiguration() const diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index 7667b77a772..00740feaa0a 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -35,6 +35,8 @@ #include #include +#include + namespace ProjectExplorer { class ExtraCompiler; } namespace CppTools { @@ -181,6 +183,7 @@ private: // CTest integration QString m_ctestPath; QList m_testNames; + QFutureSynchronizer m_futureSynchronizer; }; } // namespace Internal diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index db516a72afe..16093f079b6 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -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 @@ -4921,7 +4902,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. } diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp index c54336c0456..24b1f72f23d 100644 --- a/src/plugins/debugger/terminal.cpp +++ b/src/plugins/debugger/terminal.cpp @@ -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(); diff --git a/src/plugins/debugger/terminal.h b/src/plugins/debugger/terminal.h index 410d0fb7d91..ceacf3fddd7 100644 --- a/src/plugins/debugger/terminal.h +++ b/src/plugins/debugger/terminal.h @@ -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); diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 5681c7f15d7..34ab71154fb 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -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 diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp index 055e5cf8a7a..ac9fbab89e3 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -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(); + + if (qmlItemNode().modelNode().hasAuxiliaryData("color")) + flowColor = qmlItemNode().modelNode().auxiliaryData("color").value(); + + 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(); + 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); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h index 96031baec68..8304f1a36b7 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h @@ -128,8 +128,10 @@ protected: QList 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) diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/add.png b/src/plugins/qmldesigner/components/itemlibrary/images/add.png deleted file mode 100644 index 1b9edadee58..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/add.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/add@2x.png b/src/plugins/qmldesigner/components/itemlibrary/images/add@2x.png deleted file mode 100644 index ba352300c65..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/add@2x.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/add_unselected.png b/src/plugins/qmldesigner/components/itemlibrary/images/add_unselected.png deleted file mode 100644 index 8e237ce4a12..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/add_unselected.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/add_unselected@2x.png b/src/plugins/qmldesigner/components/itemlibrary/images/add_unselected@2x.png deleted file mode 100644 index 8be6882f3d9..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/add_unselected@2x.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/down.png b/src/plugins/qmldesigner/components/itemlibrary/images/down.png deleted file mode 100644 index d2772546bc8..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/down.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/down@2x.png b/src/plugins/qmldesigner/components/itemlibrary/images/down@2x.png deleted file mode 100644 index a635f09e554..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/down@2x.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/tab_icon.png b/src/plugins/qmldesigner/components/itemlibrary/images/tab_icon.png deleted file mode 100644 index df8abc4b794..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/tab_icon.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/tab_icon@2x.png b/src/plugins/qmldesigner/components/itemlibrary/images/tab_icon@2x.png deleted file mode 100644 index a5adb189877..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/tab_icon@2x.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc index 69ef5b2c1f8..197dd87655b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc @@ -29,17 +29,7 @@ images/asset_sound_192.png images/asset_sound_256.png images/asset_sound_384.png - images/tab_icon.png - images/tab_icon@2x.png images/x.png images/x@2x.png - images/add.png - images/add@2x.png - images/add_unselected.png - images/add_unselected@2x.png - images/down.png - images/down@2x.png - qml/libraryheader.qml - qml/addimport.qml diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp index 1cc032090e2..3176d1ebb70 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp @@ -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; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp index 55ef88a97c6..1c5b8bfcb5f 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp @@ -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; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h index ad3f1579a00..d99d4ea4dc5 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h @@ -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; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp index 649d879895d..d0a87013dd8 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp @@ -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; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h index 8993dfcb8b6..ed60c1cffe2 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h @@ -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(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 4def2f46dc3..e7276750386 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -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 &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(); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h index 2412550a3a0..8d592e29cc4 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h @@ -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(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 7ce542de024..8571f7a7d4b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -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 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() diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h index 0b78c485e58..1a34c7e96a1 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h @@ -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 diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp index 0732a08ad97..c58bed2995a 100644 --- a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp +++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp @@ -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(); diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h index a2f44dd0443..39aeb323183 100644 --- a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h +++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.h @@ -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); diff --git a/src/plugins/qmldesigner/components/texttool/textedititem.cpp b/src/plugins/qmldesigner/components/texttool/textedititem.cpp index 1ce3244cbc2..d965c4b7fd5 100644 --- a/src/plugins/qmldesigner/components/texttool/textedititem.cpp +++ b/src/plugins/qmldesigner/components/texttool/textedititem.cpp @@ -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()); activateLineEdit(); } diff --git a/src/plugins/qmldesigner/components/texttool/texttool.cpp b/src/plugins/qmldesigner/components/texttool/texttool.cpp index 76dc414c03f..a8b5ac044ae 100644 --- a/src/plugins/qmldesigner/components/texttool/texttool.cpp +++ b/src/plugins/qmldesigner/components/texttool/texttool.cpp @@ -36,6 +36,7 @@ #include "nodemetainfo.h" #include "qmlitemnode.h" +#include "richtexteditordialog.h" #include #include @@ -207,13 +208,22 @@ void TextTool::selectedItemsChanged(const QList &itemList) } if (!itemList.isEmpty()) { FormEditorItem *formEditorItem = itemList.constFirst(); - m_textItem = new TextEditItem(scene()); - textItem()->setParentItem(scene()->manipulatorLayerItem()); - textItem()->setFormEditorItem(formEditorItem); - connect(textItem(), &TextEditItem::returnPressed, [this] { - textItem()->writeTextToProperty(); + auto text = formEditorItem->qmlItemNode().instanceValue("text").toString(); + auto format = formEditorItem->qmlItemNode().instanceValue("format").value(); + 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); + connect(textItem(), &TextEditItem::returnPressed, [this] { + textItem()->writeTextToProperty(); + view()->changeToSelectionTool(); + }); + } } else { view()->changeToSelectionTool(); } diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index 8645da77935..95bf66949f5 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -205,6 +205,7 @@ public: virtual void propertiesAboutToBeRemoved(const QList& propertyList); virtual void propertiesRemoved(const QList& propertyList); virtual void variantPropertiesChanged(const QList& propertyList, PropertyChangeFlags propertyChange); + virtual void bindingPropertiesAboutToBeChanged(const QList &propertyList); virtual void bindingPropertiesChanged(const QList& propertyList, PropertyChangeFlags propertyChange); virtual void signalHandlerPropertiesChanged(const QVector& propertyList, PropertyChangeFlags propertyChange); virtual void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion); diff --git a/src/plugins/qmldesigner/designercore/include/annotation.h b/src/plugins/qmldesigner/designercore/include/annotation.h index e00481d57ab..752c817211a 100644 --- a/src/plugins/qmldesigner/designercore/include/annotation.h +++ b/src/plugins/qmldesigner/designercore/include/annotation.h @@ -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; diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp index 743d3051d7a..acf3083b3e8 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp @@ -47,6 +47,7 @@ #include +#include #include #include #include @@ -167,6 +168,20 @@ QString PuppetCreator::getStyleConfigFileName() const return QString(); } +bool PuppetCreator::usesVirtualKeyboard() const +{ +#ifndef QMLDESIGNER_TEST + if (m_target) { + auto *qmlbuild = qobject_cast(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"); diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.h b/src/plugins/qmldesigner/designercore/instances/puppetcreator.h index e001b9d0c10..f7b5761762e 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.h +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.h @@ -103,6 +103,7 @@ protected: bool useOnlyFallbackPuppet() const; QString getStyleConfigFileName() const; + bool usesVirtualKeyboard() const; private: mutable QString m_compileLog; diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index b6818d2ee67..665562a44a4 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -329,6 +329,8 @@ void AbstractView::variantPropertiesChanged(const QList& /*prop { } +void AbstractView::bindingPropertiesAboutToBeChanged(const QList &) {} + void AbstractView::bindingPropertiesChanged(const QList& /*propertyList*/, PropertyChangeFlags /*propertyChange*/) { } diff --git a/src/plugins/qmldesigner/designercore/model/annotation.cpp b/src/plugins/qmldesigner/designercore/model/annotation.cpp index e27cac283c2..f8f2edc0d8a 100644 --- a/src/plugins/qmldesigner/designercore/model/annotation.cpp +++ b/src/plugins/qmldesigner/designercore/model/annotation.cpp @@ -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()); } diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 53a1e563d42..d695be92ef2 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -767,6 +767,21 @@ void ModelPrivate::notifyNodeIdChanged(const InternalNodePointer &node, }); } +void ModelPrivate::notifyBindingPropertiesAboutToBeChanged( + const QList &internalPropertyList) +{ + notifyNodeInstanceViewLast([&](AbstractView *view) { + QList propertyList; + for (const InternalBindingPropertyPointer &bindingProperty : internalPropertyList) { + propertyList.append(BindingProperty(bindingProperty->name(), + bindingProperty->propertyOwner(), + m_model, + view)); + } + view->bindingPropertiesAboutToBeChanged(propertyList); + }); +} + void ModelPrivate::notifyBindingPropertiesChanged( const QList &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); } diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index 7a15b73468b..cc15226265e 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -149,6 +149,8 @@ public: void notifyPropertiesRemoved(const QList &propertyList); void notifyPropertiesAboutToBeRemoved(const QList &internalPropertyList); + void notifyBindingPropertiesAboutToBeChanged( + const QList &internalPropertyList); void notifyBindingPropertiesChanged(const QList &internalPropertyList, AbstractView::PropertyChangeFlags propertyChange); void notifySignalHandlerPropertiesChanged(const QVector &propertyList, AbstractView::PropertyChangeFlags propertyChange); void notifyVariantPropertiesChanged(const InternalNodePointer &node, const PropertyNameList &propertyNameList, AbstractView::PropertyChangeFlags propertyChange); diff --git a/src/plugins/qmldesigner/qmldesignerplugin.pri b/src/plugins/qmldesigner/qmldesignerplugin.pri index b11ff7a53b1..c7d3c1df056 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.pri +++ b/src/plugins/qmldesigner/qmldesignerplugin.pri @@ -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 diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index bd6c94cbb62..816c3d65732 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -984,6 +984,8 @@ Project { "shortcutmanager.h", "designermcumanager.cpp", "designermcumanager.h", + "richtexteditordialog.cpp", + "richtexteditordialog.h", ] } } diff --git a/src/plugins/qmldesigner/richtexteditordialog.cpp b/src/plugins/qmldesigner/richtexteditordialog.cpp new file mode 100644 index 00000000000..d51d063718c --- /dev/null +++ b/src/plugins/qmldesigner/richtexteditordialog.cpp @@ -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 + +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 diff --git a/src/plugins/qmldesigner/richtexteditordialog.h b/src/plugins/qmldesigner/richtexteditordialog.h new file mode 100644 index 00000000000..126be3b6a4b --- /dev/null +++ b/src/plugins/qmldesigner/richtexteditordialog.h @@ -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 +#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 diff --git a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp index e2104d7ba9b..b66aec51c28 100644 --- a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp +++ b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp @@ -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; }