Merge remote-tracking branch 'origin/14.0'

Change-Id: I0d5fd257c10eeb452d8767aba63bb7f7faacd48e
This commit is contained in:
Eike Ziller
2024-07-03 10:14:34 +02:00
49 changed files with 458 additions and 260 deletions

View File

@@ -15,6 +15,7 @@ General
* Started work on supporting Lua based plugins (registering language servers, * Started work on supporting Lua based plugins (registering language servers,
actions, preferences, and wizards) actions, preferences, and wizards)
([Documentation](https://doc-snapshots.qt.io/qtcreator-extending/lua-extensions.html)) ([Documentation](https://doc-snapshots.qt.io/qtcreator-extending/lua-extensions.html))
* Added a mode for managing extensions
* Added `Clear` and `Save Contents` to context menus of all output views * Added `Clear` and `Save Contents` to context menus of all output views
* Locator * Locator
* Added the option to show results relative to project root * Added the option to show results relative to project root
@@ -38,6 +39,9 @@ Editing
* Fixed that after hiding the editor in `Debug` mode, `Edit` mode always opened * Fixed that after hiding the editor in `Debug` mode, `Edit` mode always opened
when opening documents, even if an external editor window was available when opening documents, even if an external editor window was available
([QTCREATORBUG-30408](https://bugreports.qt.io/browse/QTCREATORBUG-30408)) ([QTCREATORBUG-30408](https://bugreports.qt.io/browse/QTCREATORBUG-30408))
* Fixed that it wasn't possible to open a file in the text editor if it was
classified as a binary file format by the MIME database
([QTCREATORBUG-31116](https://bugreports.qt.io/browse/QTCREATORBUG-31116))
### C++ ### C++
@@ -177,6 +181,12 @@ Projects
* Fixed a crash when triggering `Follow Symbol` in a CMake file that does not * Fixed a crash when triggering `Follow Symbol` in a CMake file that does not
belong to a project belong to a project
([QTCREATORBUG-31077](https://bugreports.qt.io/browse/QTCREATORBUG-31077)) ([QTCREATORBUG-31077](https://bugreports.qt.io/browse/QTCREATORBUG-31077))
* Fixed that multiple build configurations of the same type used the same
build directory
([QTCREATORBUG-26066](https://bugreports.qt.io/browse/QTCREATORBUG-26066))
* Fixed an issue with adding new files when file globs are used in the CMake
files
([QTCREATORBUG-30445](https://bugreports.qt.io/browse/QTCREATORBUG-30445))
* Presets * Presets
* Made CMake settings configurable * Made CMake settings configurable
([QTCREATORBUG-25972](https://bugreports.qt.io/browse/QTCREATORBUG-25972), ([QTCREATORBUG-25972](https://bugreports.qt.io/browse/QTCREATORBUG-25972),
@@ -291,7 +301,8 @@ Platforms
### Remote Linux ### Remote Linux
* Added the option to use SSH port forwarding for debugging * Added the `Use SSH port forwarding for debugging` option in `Preferences` >
`Devices` for a `Remote Linux Device`
* Improved the performance of the generic deployment method * Improved the performance of the generic deployment method
* Fixed that the file size check that is performed before parsing C++ files * Fixed that the file size check that is performed before parsing C++ files
could freeze Qt Creator until finished for remote projects could freeze Qt Creator until finished for remote projects
@@ -343,8 +354,10 @@ Michael Weghorn
Miikka Heikkinen Miikka Heikkinen
Orgad Shaneh Orgad Shaneh
Pranta Dastider Pranta Dastider
Ralf Habacker
Robert Löhning Robert Löhning
Sami Shalayel Sami Shalayel
Semih Yavuz
Sergey Silin Sergey Silin
Shrief Gabr Shrief Gabr
Teea Poldsam Teea Poldsam

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -14,11 +14,11 @@
\ingroup creator-reference-debugger \ingroup creator-reference-debugger
\title Supported Native Debuggers \title Supported Debuggers
\brief Summary of supported debugger versions. \brief Summary of supported debugger versions.
\QC supports native debuggers for debugging compiled code. You can use \QC to debug compiled code.
On most supported platforms, you can use the GNU Symbolic Debugger (GDB). On most supported platforms, you can use the GNU Symbolic Debugger (GDB).
On Microsoft Windows, when using the Microsoft toolchain, you need the On Microsoft Windows, when using the Microsoft toolchain, you need the
Microsoft Console Debugger (CDB). On \macos and Linux, you can use the LLDB Microsoft Console Debugger (CDB). On \macos and Linux, you can use the LLDB
@@ -34,7 +34,7 @@
\header \header
\li Platform \li Platform
\li Compiler \li Compiler
\li Native Debugger \li Debugger
\row \row
\li Linux \li Linux
\li GCC, ICC \li GCC, ICC
@@ -57,9 +57,9 @@
\li Debugging Tools for Windows/CDB \li Debugging Tools for Windows/CDB
\endtable \endtable
The debugger plugin automatically selects a suitable native debugger for \QC automatically selects a suitable debugger for
each \l{Kits}{kit} from the ones found on the computer. The automatic each \l{Kits}{kit} from the ones found on the computer. The automatic
setup fails if the native debugger is not installed on the computer or setup fails if the debugger is not installed on the computer or
if \QC does not support the installed version. if \QC does not support the installed version.
\section1 GDB Versions \section1 GDB Versions
@@ -123,7 +123,7 @@
{Mac OS X Debugging Magic}. {Mac OS X Debugging Magic}.
\section1 LLDB Versions \section1 LLDB Versions
The LLDB native debugger has similar functionality to the GDB debugger. LLDB The LLDB debugger has similar functionality to the GDB debugger. LLDB
is the default debugger in Xcode on \macos for C++ on the desktop. is the default debugger in Xcode on \macos for C++ on the desktop.
LLDB is typically used with the Clang compiler (even though you can use it LLDB is typically used with the Clang compiler (even though you can use it
with GCC, too). with GCC, too).

View File

@@ -14,8 +14,7 @@
\title Debugging \title Debugging
The \QC debugger plugin acts as an interface between the \QC You can use debuggers to:
core and external native debuggers that you can use to:
\list \list
\li Debug executable binary files - GNU Symbolic Debugger (GDB), \li Debug executable binary files - GNU Symbolic Debugger (GDB),
@@ -28,7 +27,7 @@
\section1 Setting Up the Debugger \section1 Setting Up the Debugger
The debugger plugin automatically selects a suitable native debugger for \QC automatically selects a suitable debugger for
each \l{Kits}{kit} from the ones found on your system. You can select each \l{Kits}{kit} from the ones found on your system. You can select
another kit. To specify the debugger and compiler to use for each kit, go to another kit. To specify the debugger and compiler to use for each kit, go to
\preferences > \uicontrol Kits. \preferences > \uicontrol Kits.
@@ -36,7 +35,7 @@
\image qtcreator-kits.png {Kits preferences} \image qtcreator-kits.png {Kits preferences}
You need to set up the debugger only if the automatic setup fails because You need to set up the debugger only if the automatic setup fails because
the native debugger is missing (for example, you must install the CDB the debugger is missing (for example, you must install the CDB
debugger on Windows yourself) or because \QC does not support the installed debugger on Windows yourself) or because \QC does not support the installed
version. For example, when your system does not have GDB version. For example, when your system does not have GDB
installed or the installed version is outdated, and you want to use a locally installed or the installed version is outdated, and you want to use a locally
@@ -58,11 +57,11 @@
Optionally, you can set up the Microsoft Symbol Server if you need Optionally, you can set up the Microsoft Symbol Server if you need
symbol information from Microsoft modules that is not found locally. symbol information from Microsoft modules that is not found locally.
For more information, see \l{Supported Native Debuggers} and \l{CDB Paths}. For more information, see \l{Supported Debuggers} and \l{CDB Paths}.
\section1 Launching the Debugger \section1 Launching the Debugger
The debugger plugin can run the native debuggers in various operating modes The debuggers run in various operating modes
depending on where and how you start and run the debugged process. Some of depending on where and how you start and run the debugged process. Some of
the modes are only available for a particular operating system or platform: the modes are only available for a particular operating system or platform:
@@ -93,9 +92,8 @@
\section2 GDB Run Modes \section2 GDB Run Modes
The GDB native debugger used internally by the debugger plugin runs in The GDB debugger runs in different modes to cope with the variety of
different modes to cope with the variety of supported platforms and supported platforms and environments:
environments:
\list \list
\li \e{Plain mode} debugs locally started processes that do not need \li \e{Plain mode} debugs locally started processes that do not need
@@ -591,8 +589,24 @@
in GDB, see \l{https://sourceware.org/gdb/onlinedocs/gdb/Connecting.html} in GDB, see \l{https://sourceware.org/gdb/onlinedocs/gdb/Connecting.html}
{Debugging with GDB: Connecting to a Remote Target}. {Debugging with GDB: Connecting to a Remote Target}.
\sa {Debug}{How To: Debug}, {GDB}, {Debugging}, \section1 Use SSH port forwarding
{Debuggers}, {Debugger}, {Kits}
To enable debugging on remote targets that cannot expose GDB server ports,
map the remote ports to local ports using SSH tunneling. \QC automatically
detects the local and remote ports.
To turn on SSH port forwarding:
\list 1
\li Go to \preferences > \uicontrol Devices.
\image qtcreator-preferences-devices-remote-linux.webp {Remote Linux device preferences}
\li In \uicontrol Device, select \uicontrol {Remote Linux Device}.
\li Select \uicontrol {Use SSH port forwarding for debugging}.
\li Select \uicontrol OK.
\endlist
\sa {Debug}{How To: Debug}, {Remote Linux}{How To: Develop for remote Linux},
{GDB}, {Debugging}, {Debuggers}, {Debugger}, {Kits}
*/ */
/*! /*!
@@ -770,7 +784,7 @@
The log view acts as a console, so you can send the contents The log view acts as a console, so you can send the contents
of the line under the text cursor in the log directly to the of the line under the text cursor in the log directly to the
native debugger. debugger.
\li \l{Troubleshooting Debugger} \li \l{Troubleshooting Debugger}
\l {Debugger Log} \l {Debugger Log}
@@ -865,9 +879,9 @@
\title Examine complex values in Debug views \title Examine complex values in Debug views
\QC displays the raw information from the native debuggers in a clear and \QC displays the raw information from the debuggers in a clear and
concise manner to simplify the debugging process without losing the power concise manner to simplify the debugging process without losing the power
of the native debuggers. of the debuggers.
\image qtcreator-locals.png {Locals view} \image qtcreator-locals.png {Locals view}
@@ -1150,8 +1164,8 @@
\brief View information about the modules included in a debugged application. \brief View information about the modules included in a debugged application.
The \uicontrol Modules view displays information that the debugger plugin The \uicontrol Modules view displays information about modules included in
has about modules included in the application that is being debugged. the application that is being debugged.
A module is: A module is:
@@ -1389,13 +1403,13 @@
\li Set \l{Debugger}{debugger preferences}. \li Set \l{Debugger}{debugger preferences}.
\endlist \endlist
\section1 Directly Interacting with Native Debuggers \section1 Directly Interacting with Debuggers
You can use the left pane of the \uicontrol {Debugger Log} view to directly You can use the left pane of the \uicontrol {Debugger Log} view to directly
interact with the command line of the native debugger. interact with the command line of the debugger.
Press \key {Ctrl+Enter} to send the contents of the line under the Press \key {Ctrl+Enter} to send the contents of the line under the
text cursor to the native debugger. Or, enter the command in the text cursor to the debugger. Or, enter the command in the
\uicontrol Command field. The right side pane of the \uicontrol Command field. The right side pane of the
\uicontrol {Debugger Log} view shows the command output. \uicontrol {Debugger Log} view shows the command output.
@@ -1464,7 +1478,7 @@
\brief Load, customize, and add debugging helpers. \brief Load, customize, and add debugging helpers.
\QC uses Python scripts to translate raw memory contents and type information \QC uses Python scripts to translate raw memory contents and type information
data from native debugger backends (GDB, LLDB, and CDB are currently supported) data from debugger backends (GDB, LLDB, and CDB are currently supported)
into the form presented to the user in the into the form presented to the user in the
\l {Local Variables and Function Parameters}{Locals} \l {Local Variables and Function Parameters}{Locals}
and \l {Evaluating Expressions}{Expressions} views. and \l {Evaluating Expressions}{Expressions} views.
@@ -1520,7 +1534,7 @@
of Qt, or of your own library, at the same time. of Qt, or of your own library, at the same time.
To add debugging helpers for custom types, add debugging helper To add debugging helpers for custom types, add debugging helper
implementations to the startup file of the native debuggers (for example, implementations to the startup file of the debuggers (for example,
\c{~/.gdbinit} or \c{~/.lldbinit}) or specify them directly in the \c{~/.gdbinit} or \c{~/.lldbinit}) or specify them directly in the
\uicontrol {Additional Startup Commands} in \preferences > \uicontrol {Additional Startup Commands} in \preferences >
\uicontrol Debugger > \uicontrol GDB. \uicontrol Debugger > \uicontrol GDB.
@@ -1733,7 +1747,7 @@
\endcode \endcode
\li \c{putCallItem(self, name, rettype, value, func, *args)} - Uses the \li \c{putCallItem(self, name, rettype, value, func, *args)} - Uses the
native debugger backend to place the function call \c func returning debugger backend to place the function call \c func returning
\c rettype on the value specified by \a {value} and to output the \c rettype on the value specified by \a {value} and to output the
resulting item. resulting item.
@@ -1880,7 +1894,7 @@
an integral or floating point type. an integral or floating point type.
Type objects, that is, instances of the \c{Dumper.Type} class, can be Type objects, that is, instances of the \c{Dumper.Type} class, can be
created by native debugger backends, usually by evaluating Debug Information created by debugger backends, usually by evaluating Debug Information
built into or shipped alongside the debugged binary, or created on-the-fly built into or shipped alongside the debugged binary, or created on-the-fly
by the debugging helper. by the debugging helper.
@@ -2110,7 +2124,7 @@
\l {Run on many platforms}{build and run kit selector} \l {Run on many platforms}{build and run kit selector}
picked a runnable target and you can run the application. picked a runnable target and you can run the application.
\li Make sure the debugger is \l{Supported Native Debuggers}{set up properly}. \li Make sure the debugger is \l{Supported Debuggers}{set up properly}.
\li In the \uicontrol Debug mode, go to \uicontrol View > \li In the \uicontrol Debug mode, go to \uicontrol View >
\uicontrol Views > \uicontrol {Debugger Log} to open the \uicontrol Views > \uicontrol {Debugger Log} to open the

View File

@@ -66,8 +66,7 @@
\section1 Debug \section1 Debug
Use native debuggers to inspect the state of your application while Use debuggers to inspect the state of your application while it is running.
debugging.
\generatelist creator-how-to-debug \generatelist creator-how-to-debug

View File

@@ -143,7 +143,7 @@
You must use Python version 2.6 or 2.7. You must use Python version 2.6 or 2.7.
For more information, see \l{Supported Native Debuggers}. For more information, see \l{Supported Debuggers}.
\b {How do I generate a core file in \QC?} \b {How do I generate a core file in \QC?}

View File

@@ -35,5 +35,6 @@
it is compatible with the GDB on the host. it is compatible with the GDB on the host.
\sa {Remote Linux}{How To: Develop for remote Linux}, \sa {Remote Linux}{How To: Develop for remote Linux},
{Run on many platforms}, {Compilers}, {Embedded Platforms}, {Kits} {Debug remotely with GDB}, {Run on many platforms}, {Compilers},
{Embedded Platforms}, {Kits}
*/ */

View File

@@ -138,6 +138,6 @@
\include qtcreator-add-linux-device.qdocinc {add linux device} {Remote Linux Device} \include qtcreator-add-linux-device.qdocinc {add linux device} {Remote Linux Device}
\sa {Remote Linux}{How To: Develop for remote Linux}, \sa {Remote Linux}{How To: Develop for remote Linux},
{Developing for Remote Linux Devices}, {Debug remotely with GDB}, {Developing for Remote Linux Devices},
{Remote Linux Deploy Configuration} {Remote Linux Deploy Configuration}
*/ */

View File

@@ -266,10 +266,10 @@
to find the next one. to find the next one.
\endlist \endlist
\QC integrates several native debuggers for inspecting the state of \QC integrates several debuggers for inspecting the state of your
your application while debugging. The debugger plugin automatically selects application. It automatically selects a suitable debugger for each
a suitable native debugger for each kit from the ones it finds on the kit from the ones it finds on the computer. Edit the kits to override
computer. Edit the kits to override this choice. this choice.
If you install \QC with \QOI, the GNU Symbolic Debugger is installed If you install \QC with \QOI, the GNU Symbolic Debugger is installed
automatically and you should be ready to start debugging after you create automatically and you should be ready to start debugging after you create

View File

@@ -21,7 +21,7 @@
\section1 Debuggers \section1 Debuggers
Set up and use native debuggers to debug executable binary files, as well as Set up and use debuggers to debug executable binary files, as well as
QML, Java, and Python source code. QML, Java, and Python source code.
\annotatedlist creator-reference-debugger \annotatedlist creator-reference-debugger

View File

@@ -15,12 +15,11 @@
\title Add debuggers \title Add debuggers
The \QC debugger plugin acts as an interface between the \QC core and You can use debuggers, such as the GNU Symbolic Debugger (GDB),
external native debuggers such as the GNU Symbolic Debugger (GDB),
the Microsoft Console Debugger (CDB), a QML/JavaScript debugger, and the the Microsoft Console Debugger (CDB), a QML/JavaScript debugger, and the
debugger of the low level virtual machine (LLVM) project, LLDB. debugger of the low level virtual machine (LLVM) project, LLDB.
The debugger plugin automatically selects a suitable native debugger for \QC automatically selects a suitable debugger for
each \l{Kits}{kit} from the ones found on your system. each \l{Kits}{kit} from the ones found on your system.
To override this choice, select \preferences > \uicontrol Kits. To override this choice, select \preferences > \uicontrol Kits.
@@ -75,6 +74,6 @@
The debugger disappears from the list when you select \uicontrol Apply. The debugger disappears from the list when you select \uicontrol Apply.
Until then, you can cancel the deletion by clicking \uicontrol Restore. Until then, you can cancel the deletion by clicking \uicontrol Restore.
\sa {Debugging}, {Debuggers}, {Debugger}, {Supported Native Debuggers}, \sa {Debugging}, {Debuggers}, {Debugger}, {Supported Debuggers},
{Troubleshooting Debugger} {Troubleshooting Debugger}
*/ */

View File

@@ -26,7 +26,7 @@
\li \l{Run Python applications} \li \l{Run Python applications}
\li \l{Python Run Settings} \li \l{Python Run Settings}
\li \l{PDB versions} \li \l{PDB versions}
\li \l{Supported Native Debuggers} \li \l{Supported Debuggers}
\endlist \endlist
For more information about developing with Qt for Python, including For more information about developing with Qt for Python, including

View File

@@ -99,8 +99,8 @@ public:
iter = iter->next; iter = iter->next;
return *this; return *this;
} }
bool operator==(const ListIterator &other) { return iter == other.iter; } bool operator==(const ListIterator &other) const { return iter == other.iter; }
bool operator!=(const ListIterator &other) { return iter != other.iter; } bool operator!=(const ListIterator &other) const { return iter != other.iter; }
}; };
ListIterator begin() { return {this}; } ListIterator begin() { return {this}; }
ListIterator end() { return {nullptr}; } ListIterator end() { return {nullptr}; }

View File

@@ -330,13 +330,10 @@ static QTextLine currentTextLine(const QTextCursor &cursor)
return layout->lineForTextPosition(relativePos); return layout->lineForTextPosition(relativePos);
} }
bool MultiTextCursor::multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey) bool MultiTextCursor::multiCursorEvent(
QKeyEvent *e, QKeySequence::StandardKey matchKey, Qt::KeyboardModifiers filterModifiers)
{ {
uint searchkey = (e->modifiers() | e->key()) uint searchkey = (e->modifiers() | e->key()) & ~(filterModifiers | Qt::AltModifier);
& ~(Qt::KeypadModifier
| Qt::GroupSwitchModifier
| Qt::AltModifier
| Qt::ShiftModifier);
const QList<QKeySequence> bindings = QKeySequence::keyBindings(matchKey); const QList<QKeySequence> bindings = QKeySequence::keyBindings(matchKey);
return bindings.contains(QKeySequence(searchkey)); return bindings.contains(QKeySequence(searchkey));
@@ -348,42 +345,42 @@ bool MultiTextCursor::handleMoveKeyEvent(QKeyEvent *e,
{ {
if (e->modifiers() & Qt::AltModifier && !Utils::HostOsInfo::isMacHost()) { if (e->modifiers() & Qt::AltModifier && !Utils::HostOsInfo::isMacHost()) {
QTextCursor::MoveOperation op = QTextCursor::NoMove; QTextCursor::MoveOperation op = QTextCursor::NoMove;
if (multiCursorAddEvent(e, QKeySequence::MoveToNextWord)) { if (multiCursorEvent(e, QKeySequence::MoveToNextWord)) {
op = QTextCursor::WordRight; op = QTextCursor::WordRight;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToPreviousWord)) { } else if (multiCursorEvent(e, QKeySequence::MoveToPreviousWord)) {
op = QTextCursor::WordLeft; op = QTextCursor::WordLeft;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToEndOfBlock)) { } else if (multiCursorEvent(e, QKeySequence::MoveToEndOfBlock)) {
op = QTextCursor::EndOfBlock; op = QTextCursor::EndOfBlock;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToStartOfBlock)) { } else if (multiCursorEvent(e, QKeySequence::MoveToStartOfBlock)) {
op = QTextCursor::StartOfBlock; op = QTextCursor::StartOfBlock;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToNextLine)) { } else if (multiCursorEvent(e, QKeySequence::MoveToNextLine, Qt::ShiftModifier)) {
op = QTextCursor::Down; op = QTextCursor::Down;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToPreviousLine)) { } else if (multiCursorEvent(e, QKeySequence::MoveToPreviousLine, Qt::ShiftModifier)) {
op = QTextCursor::Up; op = QTextCursor::Up;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToStartOfLine)) { } else if (multiCursorEvent(e, QKeySequence::MoveToStartOfLine)) {
op = QTextCursor::StartOfLine; op = QTextCursor::StartOfLine;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToEndOfLine)) { } else if (multiCursorEvent(e, QKeySequence::MoveToEndOfLine)) {
op = QTextCursor::EndOfLine; op = QTextCursor::EndOfLine;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToStartOfDocument)) { } else if (multiCursorEvent(e, QKeySequence::MoveToStartOfDocument)) {
op = QTextCursor::Start; op = QTextCursor::Start;
} else if (multiCursorAddEvent(e, QKeySequence::MoveToEndOfDocument)) { } else if (multiCursorEvent(e, QKeySequence::MoveToEndOfDocument)) {
op = QTextCursor::End; op = QTextCursor::End;
} else {
return false;
} }
const std::list<QTextCursor> cursors = m_cursorList; if (op != QTextCursor::NoMove) {
for (QTextCursor cursor : cursors) { const std::list<QTextCursor> cursors = m_cursorList;
if (camelCaseNavigationEnabled && op == QTextCursor::WordRight) for (QTextCursor cursor : cursors) {
CamelCaseCursor::right(&cursor, edit, QTextCursor::MoveAnchor); if (camelCaseNavigationEnabled && op == QTextCursor::WordRight)
else if (camelCaseNavigationEnabled && op == QTextCursor::WordLeft) CamelCaseCursor::right(&cursor, edit, QTextCursor::MoveAnchor);
CamelCaseCursor::left(&cursor, edit, QTextCursor::MoveAnchor); else if (camelCaseNavigationEnabled && op == QTextCursor::WordLeft)
else CamelCaseCursor::left(&cursor, edit, QTextCursor::MoveAnchor);
cursor.movePosition(op, QTextCursor::MoveAnchor); else
cursor.movePosition(op, QTextCursor::MoveAnchor);
addCursor(cursor); addCursor(cursor);
}
return true;
} }
return true;
} }
for (auto it = m_cursorList.begin(); it != m_cursorList.end(); ++it) { for (auto it = m_cursorList.begin(); it != m_cursorList.end(); ++it) {
@@ -395,28 +392,28 @@ bool MultiTextCursor::handleMoveKeyEvent(QKeyEvent *e,
op = QTextCursor::Right; op = QTextCursor::Right;
} else if (e == QKeySequence::MoveToPreviousChar) { } else if (e == QKeySequence::MoveToPreviousChar) {
op = QTextCursor::Left; op = QTextCursor::Left;
} else if (e == QKeySequence::SelectNextChar) { } else if (multiCursorEvent(e, QKeySequence::SelectNextChar)) {
op = QTextCursor::Right; op = QTextCursor::Right;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectPreviousChar) { } else if (multiCursorEvent(e, QKeySequence::SelectPreviousChar)) {
op = QTextCursor::Left; op = QTextCursor::Left;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectNextWord) { } else if (multiCursorEvent(e, QKeySequence::SelectNextWord)) {
op = QTextCursor::WordRight; op = QTextCursor::WordRight;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectPreviousWord) { } else if (multiCursorEvent(e, QKeySequence::SelectPreviousWord)) {
op = QTextCursor::WordLeft; op = QTextCursor::WordLeft;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectStartOfLine) { } else if (multiCursorEvent(e, QKeySequence::SelectStartOfLine)) {
op = QTextCursor::StartOfLine; op = QTextCursor::StartOfLine;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectEndOfLine) { } else if (multiCursorEvent(e, QKeySequence::SelectEndOfLine)) {
op = QTextCursor::EndOfLine; op = QTextCursor::EndOfLine;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectStartOfBlock) { } else if (multiCursorEvent(e, QKeySequence::SelectStartOfBlock)) {
op = QTextCursor::StartOfBlock; op = QTextCursor::StartOfBlock;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectEndOfBlock) { } else if (multiCursorEvent(e, QKeySequence::SelectEndOfBlock)) {
op = QTextCursor::EndOfBlock; op = QTextCursor::EndOfBlock;
mode = QTextCursor::KeepAnchor; mode = QTextCursor::KeepAnchor;
} else if (e == QKeySequence::SelectStartOfDocument) { } else if (e == QKeySequence::SelectStartOfDocument) {

View File

@@ -108,7 +108,10 @@ public:
const_iterator constBegin() const { return m_cursorMap.cbegin(); } const_iterator constBegin() const { return m_cursorMap.cbegin(); }
const_iterator constEnd() const { return m_cursorMap.cend(); } const_iterator constEnd() const { return m_cursorMap.cend(); }
static bool multiCursorAddEvent(QKeyEvent *e, QKeySequence::StandardKey matchKey); static bool multiCursorEvent(
QKeyEvent *e,
QKeySequence::StandardKey matchKey,
Qt::KeyboardModifiers additionalFilterModifier = {});
private: private:
std::list<QTextCursor> m_cursorList; std::list<QTextCursor> m_cursorList;

View File

@@ -20,10 +20,10 @@ namespace Android::Internal::AndroidAvdManager {
static Q_LOGGING_CATEGORY(avdManagerLog, "qtc.android.avdManager", QtWarningMsg) static Q_LOGGING_CATEGORY(avdManagerLog, "qtc.android.avdManager", QtWarningMsg)
QString startAvd(const QString &name) QString startAvd(const QString &name, const std::optional<QFuture<void>> &future)
{ {
if (!findAvd(name).isEmpty() || startAvdAsync(name)) if (!findAvd(name).isEmpty() || startAvdAsync(name))
return waitForAvd(name); return waitForAvd(name, future);
return {}; return {};
} }

View File

@@ -8,7 +8,7 @@
namespace Android::Internal::AndroidAvdManager { namespace Android::Internal::AndroidAvdManager {
QString startAvd(const QString &name); QString startAvd(const QString &name, const std::optional<QFuture<void>> &future = {});
bool startAvdAsync(const QString &avdName); bool startAvdAsync(const QString &avdName);
QString findAvd(const QString &avdName); QString findAvd(const QString &avdName);
QString waitForAvd(const QString &avdName, const std::optional<QFuture<void>> &future = {}); QString waitForAvd(const QString &avdName, const std::optional<QFuture<void>> &future = {});

View File

@@ -111,15 +111,14 @@ static void startAvd(const IDevice::Ptr &device, QWidget *parent)
const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(device.get()); const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(device.get());
const QString name = androidDev->avdName(); const QString name = androidDev->avdName();
qCDebug(androidDeviceLog, "Starting Android AVD id \"%s\".", qPrintable(name)); qCDebug(androidDeviceLog, "Starting Android AVD id \"%s\".", qPrintable(name));
auto future = Utils::asyncRun([name, device] { Utils::futureSynchronizer()->addFuture(Utils::asyncRun([name, device](QPromise<void> &promise) {
const QString serialNumber = AndroidAvdManager::startAvd(name); const QString serialNumber = AndroidAvdManager::startAvd(name, promise.future());
// Mark the AVD as ReadyToUse once we know it's started // Mark the AVD as ReadyToUse once we know it's started
if (!serialNumber.isEmpty()) { if (!serialNumber.isEmpty()) {
DeviceManager *const devMgr = DeviceManager::instance(); DeviceManager *const devMgr = DeviceManager::instance();
devMgr->setDeviceState(device->id(), IDevice::DeviceReadyToUse); devMgr->setDeviceState(device->id(), IDevice::DeviceReadyToUse);
} }
}); }));
// TODO: use future!
} }
static void setEmulatorArguments(QWidget *parent) static void setEmulatorArguments(QWidget *parent)

View File

@@ -29,43 +29,15 @@ DiagnosticMark::DiagnosticMark(const Diagnostic &diagnostic, TextDocument *docum
: TextMark(document, diagnostic.location.line, clangToolsCategory()) : TextMark(document, diagnostic.location.line, clangToolsCategory())
, m_diagnostic(diagnostic) , m_diagnostic(diagnostic)
{ {
setSettingsPage(Constants::SETTINGS_PAGE_ID); initialize();
const bool isError = diagnostic.type == "error" || diagnostic.type == "fatal";
setColor(isError ? Theme::CodeModel_Error_TextMarkColor : Theme::CodeModel_Warning_TextMarkColor);
setPriority(isError ? TextEditor::TextMark::HighPriority : TextEditor::TextMark::NormalPriority);
QIcon markIcon = diagnostic.icon();
setIcon(markIcon.isNull() ? Icons::CODEMODEL_WARNING.icon() : markIcon);
setToolTip(createDiagnosticToolTipString(diagnostic, std::nullopt, true));
setLineAnnotation(diagnostic.description);
setActionsProvider([diagnostic] {
// Copy to clipboard action
QList<QAction *> actions;
QAction *action = new QAction();
action->setIcon(Icon::fromTheme("edit-copy"));
action->setToolTip(Tr::tr("Copy to Clipboard"));
QObject::connect(action, &QAction::triggered, [diagnostic] {
const QString text = createFullLocationString(diagnostic.location)
+ ": "
+ diagnostic.description;
setClipboardAndSelection(text);
});
actions << action;
// Disable diagnostic action
action = new QAction();
action->setIcon(Icons::BROKEN.icon());
action->setToolTip(Tr::tr("Disable Diagnostic"));
QObject::connect(action, &QAction::triggered, [diagnostic] { disableChecks({diagnostic}); });
actions << action;
return actions;
});
} }
DiagnosticMark::DiagnosticMark(const Diagnostic &diagnostic) DiagnosticMark::DiagnosticMark(const Diagnostic &diagnostic)
: TextMark(diagnostic.location.filePath, diagnostic.location.line, clangToolsCategory()) : TextMark(diagnostic.location.filePath, diagnostic.location.line, clangToolsCategory())
, m_diagnostic(diagnostic) , m_diagnostic(diagnostic)
{} {
initialize();
}
void DiagnosticMark::disable() void DiagnosticMark::disable()
{ {
@@ -89,6 +61,41 @@ Diagnostic DiagnosticMark::diagnostic() const
return m_diagnostic; return m_diagnostic;
} }
void DiagnosticMark::initialize()
{
setSettingsPage(Constants::SETTINGS_PAGE_ID);
const bool isError = m_diagnostic.type == "error" || m_diagnostic.type == "fatal";
setColor(isError ? Theme::CodeModel_Error_TextMarkColor : Theme::CodeModel_Warning_TextMarkColor);
setPriority(isError ? TextEditor::TextMark::HighPriority : TextEditor::TextMark::NormalPriority);
QIcon markIcon = m_diagnostic.icon();
setIcon(markIcon.isNull() ? Icons::CODEMODEL_WARNING.icon() : markIcon);
setToolTip(createDiagnosticToolTipString(m_diagnostic, std::nullopt, true));
setLineAnnotation(m_diagnostic.description);
setActionsProvider([diagnostic = m_diagnostic] {
// Copy to clipboard action
QList<QAction *> actions;
QAction *action = new QAction();
action->setIcon(Icon::fromTheme("edit-copy"));
action->setToolTip(Tr::tr("Copy to Clipboard"));
QObject::connect(action, &QAction::triggered, [diagnostic] {
const QString text = createFullLocationString(diagnostic.location)
+ ": "
+ diagnostic.description;
setClipboardAndSelection(text);
});
actions << action;
// Disable diagnostic action
action = new QAction();
action->setIcon(Icons::BROKEN.icon());
action->setToolTip(Tr::tr("Disable Diagnostic"));
QObject::connect(action, &QAction::triggered, [diagnostic] { disableChecks({diagnostic}); });
actions << action;
return actions;
});
}
} // namespace Internal } // namespace Internal
} // namespace ClangTools } // namespace ClangTools

View File

@@ -25,6 +25,7 @@ public:
std::optional<CppEditor::ClangToolType> toolType; std::optional<CppEditor::ClangToolType> toolType;
private: private:
void initialize();
const Diagnostic m_diagnostic; const Diagnostic m_diagnostic;
bool m_enabled = true; bool m_enabled = true;
}; };

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 B

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 538 B

After

Width:  |  Height:  |  Size: 540 B

View File

@@ -214,21 +214,13 @@ void RichTextDelegate::paint(QPainter *painter,
m_doc.setHtml(options.text); m_doc.setHtml(options.text);
m_doc.setTextWidth(options.rect.width()); m_doc.setTextWidth(options.rect.width());
options.text = ""; options.text = "";
options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter); options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter, options.widget);
painter->translate(options.rect.left(), options.rect.top()); painter->translate(options.rect.left(), options.rect.top());
QRect clip(0, 0, options.rect.width(), options.rect.height()); QRect clip(0, 0, options.rect.width(), options.rect.height());
QAbstractTextDocumentLayout::PaintContext paintContext; QAbstractTextDocumentLayout::PaintContext paintContext;
paintContext.palette = options.palette; paintContext.palette = options.palette;
painter->setClipRect(clip); painter->setClipRect(clip);
paintContext.clip = clip; paintContext.clip = clip;
if (qobject_cast<const QAbstractItemView *>(options.widget)->selectionModel()->isSelected(index)) {
QAbstractTextDocumentLayout::Selection selection;
selection.cursor = QTextCursor(&m_doc);
selection.cursor.select(QTextCursor::Document);
selection.format.setBackground(options.palette.brush(QPalette::Highlight));
selection.format.setForeground(options.palette.brush(QPalette::HighlightedText));
paintContext.selections << selection;
}
m_doc.documentLayout()->draw(painter, paintContext); m_doc.documentLayout()->draw(painter, paintContext);
painter->restore(); painter->restore();
} }

View File

@@ -349,9 +349,8 @@ void ModeManager::currentTabChanged(int index)
if (!mode) if (!mode)
return; return;
// FIXME: This hardcoded context update is required for the Debug and Edit modes, since // Set the mode's context regardless of focus widget.
// they use the editor widget, which is already a context widget so the main window won't // Whenever a mode is active, it's Context is active.
// go further up the parent tree to find the mode context.
ICore::updateAdditionalContexts(d->m_addedContexts, mode->context()); ICore::updateAdditionalContexts(d->m_addedContexts, mode->context());
d->m_addedContexts = mode->context(); d->m_addedContexts = mode->context();

View File

@@ -19,10 +19,12 @@
namespace Cppcheck::Internal { namespace Cppcheck::Internal {
ManualRunDialog::ManualRunDialog(const ProjectExplorer::Project *project) ManualRunDialog::ManualRunDialog(const ProjectExplorer::Project *project,
CppcheckSettings *settings)
: m_model(new ProjectExplorer::SelectableFilesFromDirModel(this)) : m_model(new ProjectExplorer::SelectableFilesFromDirModel(this))
{ {
QTC_ASSERT(project, return ); QTC_ASSERT(project, return );
QTC_ASSERT(settings, return);
setWindowTitle(Tr::tr("Cppcheck Run Configuration")); setWindowTitle(Tr::tr("Cppcheck Run Configuration"));
@@ -52,9 +54,7 @@ ManualRunDialog::ManualRunDialog(const ProjectExplorer::Project *project)
analyzeButton->setEnabled(m_model->hasCheckedFiles()); analyzeButton->setEnabled(m_model->hasCheckedFiles());
}); });
m_manualRunSettings.readSettings(); auto optionsWidget = settings->layouter()().emerge();
m_manualRunSettings.setAutoApply(true);
auto optionsWidget = m_manualRunSettings.layouter()().emerge();
auto layout = new QVBoxLayout(this); auto layout = new QVBoxLayout(this);
layout->addWidget(optionsWidget); layout->addWidget(optionsWidget);

View File

@@ -3,8 +3,6 @@
#pragma once #pragma once
#include "cppchecksettings.h"
#include <QDialog> #include <QDialog>
namespace Utils { namespace Utils {
@@ -19,18 +17,18 @@ class SelectableFilesFromDirModel;
namespace Cppcheck::Internal { namespace Cppcheck::Internal {
class CppcheckSettings;
class ManualRunDialog : public QDialog class ManualRunDialog : public QDialog
{ {
public: public:
explicit ManualRunDialog(const ProjectExplorer::Project *project); explicit ManualRunDialog(const ProjectExplorer::Project *project, CppcheckSettings *settings);
Utils::FilePaths filePaths() const; Utils::FilePaths filePaths() const;
QSize sizeHint() const override; QSize sizeHint() const override;
const CppcheckSettings &manualRunSettings() const { return m_manualRunSettings; }
private: private:
ProjectExplorer::SelectableFilesFromDirModel *m_model; ProjectExplorer::SelectableFilesFromDirModel *m_model;
CppcheckSettings m_manualRunSettings;
}; };
} // Cppcheck::Internal } // Cppcheck::Internal

View File

@@ -40,6 +40,7 @@ class CppcheckPluginPrivate final : public QObject
{ {
public: public:
explicit CppcheckPluginPrivate(); explicit CppcheckPluginPrivate();
~CppcheckPluginPrivate();
CppcheckTextMarkManager marks; CppcheckTextMarkManager marks;
CppcheckTool tool{marks, Constants::CHECK_PROGRESS_ID}; CppcheckTool tool{marks, Constants::CHECK_PROGRESS_ID};
@@ -49,9 +50,12 @@ public:
Utils::Perspective perspective{Constants::PERSPECTIVE_ID, ::Cppcheck::Tr::tr("Cppcheck")}; Utils::Perspective perspective{Constants::PERSPECTIVE_ID, ::Cppcheck::Tr::tr("Cppcheck")};
Action *manualRunAction = nullptr; Action *manualRunAction = nullptr;
QHash<Project *, CppcheckSettings *> projectSettings;
void startManualRun(); void startManualRun();
void updateManualRunAction(); void updateManualRunAction();
void saveProjectSettings(Project *project);
void loadProjectSettings(Project *project);
}; };
CppcheckPluginPrivate::CppcheckPluginPrivate() CppcheckPluginPrivate::CppcheckPluginPrivate()
@@ -104,6 +108,29 @@ CppcheckPluginPrivate::CppcheckPluginPrivate()
action, &QAction::setEnabled); action, &QAction::setEnabled);
perspective.addToolBarAction(action); perspective.addToolBarAction(action);
} }
connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged,
this, [this](Project *project) {
if (!project)
return;
CppcheckSettings *settings = projectSettings.value(project, nullptr);
if (!settings) {
settings = new CppcheckSettings;
settings->readSettings();
settings->setAutoApply(true);
connect(project, &Project::aboutToSaveSettings,
this, [this, project]{ saveProjectSettings(project); });
connect(project, &Project::settingsLoaded,
this, [this, project]{ loadProjectSettings(project); });
projectSettings.insert(project, settings);
loadProjectSettings(project);
}
});
}
CppcheckPluginPrivate::~CppcheckPluginPrivate()
{
qDeleteAll(projectSettings);
projectSettings.clear();
} }
void CppcheckPluginPrivate::startManualRun() void CppcheckPluginPrivate::startManualRun()
@@ -112,7 +139,9 @@ void CppcheckPluginPrivate::startManualRun()
if (!project) if (!project)
return; return;
ManualRunDialog dialog(project); CppcheckSettings *settings = projectSettings.value(project, nullptr);
QTC_ASSERT(settings, return);
ManualRunDialog dialog(project, settings);
if (dialog.exec() == ManualRunDialog::Rejected) if (dialog.exec() == ManualRunDialog::Rejected)
return; return;
@@ -123,7 +152,7 @@ void CppcheckPluginPrivate::startManualRun()
return; return;
manualRunTool.setProject(project); manualRunTool.setProject(project);
manualRunTool.updateOptions(dialog.manualRunSettings()); manualRunTool.updateOptions(*settings);
manualRunTool.check(files); manualRunTool.check(files);
perspective.select(); perspective.select();
} }
@@ -138,6 +167,30 @@ void CppcheckPluginPrivate::updateManualRunAction()
manualRunAction->setEnabled(canRun); manualRunAction->setEnabled(canRun);
} }
void CppcheckPluginPrivate::saveProjectSettings(Project *project)
{
QTC_ASSERT(project, return);
CppcheckSettings *settings = projectSettings.value(project, nullptr);
QTC_ASSERT(settings, return);
Store store;
settings->toMap(store);
project->setNamedSettings("CppcheckManual", Utils::variantFromStore(store));
}
void CppcheckPluginPrivate::loadProjectSettings(Project *project)
{
QTC_ASSERT(project, return);
CppcheckSettings *settings = projectSettings.value(project, nullptr);
QTC_ASSERT(settings, return);
const QVariant variant = project->namedSettings("CppcheckManual");
if (!variant.isValid())
return;
Store store = Utils::storeFromVariant(project->namedSettings("CppcheckManual"));
settings->fromMap(store);
}
class CppcheckPlugin final : public ExtensionSystem::IPlugin class CppcheckPlugin final : public ExtensionSystem::IPlugin
{ {
Q_OBJECT Q_OBJECT

View File

@@ -5,6 +5,8 @@ add_qtc_plugin(ExtensionManager
extensionmanagerconstants.h extensionmanagerconstants.h
extensionmanagerplugin.cpp extensionmanagerplugin.cpp
extensionmanagertr.h extensionmanagertr.h
extensionmanagersettings.cpp
extensionmanagersettings.h
extensionmanagerwidget.cpp extensionmanagerwidget.cpp
extensionmanagerwidget.h extensionmanagerwidget.h
extensionsbrowser.cpp extensionsbrowser.cpp

View File

@@ -13,6 +13,8 @@ QtcPlugin {
"extensionmanagerconstants.h", "extensionmanagerconstants.h",
"extensionmanagerplugin.cpp", "extensionmanagerplugin.cpp",
"extensionmanagertr.h", "extensionmanagertr.h",
"extensionmanagersettings.cpp",
"extensionmanagersettings.h",
"extensionmanagerwidget.cpp", "extensionmanagerwidget.cpp",
"extensionmanagerwidget.h", "extensionmanagerwidget.h",
"extensionsbrowser.cpp", "extensionsbrowser.cpp",

View File

@@ -0,0 +1,59 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "extensionmanagersettings.h"
#include "extensionmanagertr.h"
#include <coreplugin/coreconstants.h>
#include <coreplugin/dialogs/ioptionspage.h>
#include <utils/layoutbuilder.h>
namespace ExtensionManager::Internal {
ExtensionManagerSettings &settings()
{
static ExtensionManagerSettings theExtensionManagerSettings;
return theExtensionManagerSettings;
}
ExtensionManagerSettings::ExtensionManagerSettings()
{
setAutoApply(false);
setSettingsGroup("ExtensionManager");
externalRepoUrl.setDefaultValue("https://qc-extensions.qt.io");
externalRepoUrl.setReadOnly(true);
useExternalRepo.setSettingsKey("UseExternalRepo");
useExternalRepo.setLabelText(Tr::tr("Use external repository"));
useExternalRepo.setToolTip(Tr::tr("Repository: %1").arg(externalRepoUrl()));
useExternalRepo.setDefaultValue(false);
setLayouter([this] {
using namespace Layouting;
return Column {
useExternalRepo,
st
};
});
readSettings();
}
class ExtensionManagerSettingsPage : public Core::IOptionsPage
{
public:
ExtensionManagerSettingsPage()
{
setId("ExtensionManager");
setDisplayName(Tr::tr("Extensions"));
setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
setSettingsProvider([] { return &settings(); });
}
};
const ExtensionManagerSettingsPage settingsPage;
} // ExtensionManager::Internal

View File

@@ -0,0 +1,21 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <utils/aspects.h>
namespace ExtensionManager::Internal {
class ExtensionManagerSettings final : public Utils::AspectContainer
{
public:
ExtensionManagerSettings();
Utils::StringAspect externalRepoUrl{this};
Utils::BoolAspect useExternalRepo{this};
};
ExtensionManagerSettings &settings();
} // ExtensionManager::Internal

View File

@@ -5,7 +5,7 @@
#include "extensionmanagertr.h" #include "extensionmanagertr.h"
#include "extensionsmodel.h" #include "extensionsmodel.h"
#include "utils/hostosinfo.h" #include "extensionmanagersettings.h"
#ifdef WITH_TESTS #ifdef WITH_TESTS
#include "extensionmanager_test.h" #include "extensionmanager_test.h"
@@ -29,6 +29,7 @@
#include <utils/elidinglabel.h> #include <utils/elidinglabel.h>
#include <utils/fancylineedit.h> #include <utils/fancylineedit.h>
#include <utils/hostosinfo.h>
#include <utils/icon.h> #include <utils/icon.h>
#include <utils/layoutbuilder.h> #include <utils/layoutbuilder.h>
#include <utils/networkaccessmanager.h> #include <utils/networkaccessmanager.h>
@@ -399,14 +400,18 @@ void ExtensionsBrowser::fetchExtensions()
// d->model->setExtensionsJson(testData("defaultpacks")); return; // d->model->setExtensionsJson(testData("defaultpacks")); return;
#endif // WITH_TESTS #endif // WITH_TESTS
if (!settings().useExternalRepo()) {
d->model->setExtensionsJson({});
return;
}
using namespace Tasking; using namespace Tasking;
const auto onQuerySetup = [this](NetworkQuery &query) { const auto onQuerySetup = [this](NetworkQuery &query) {
const QString host = "https://qc-extensions.qt.io";
const QString url = "%1/api/v1/search?request="; const QString url = "%1/api/v1/search?request=";
const QString requestTemplate const QString requestTemplate
= R"({"version":"%1","host_os":"%2","host_os_version":"%3","host_architecture":"%4","page_size":200})"; = R"({"version":"%1","host_os":"%2","host_os_version":"%3","host_architecture":"%4","page_size":200})";
const QString request = url.arg(host) + requestTemplate const QString request = url.arg(settings().externalRepoUrl()) + requestTemplate
.arg(QCoreApplication::applicationVersion()) .arg(QCoreApplication::applicationVersion())
.arg(osTypeToString(HostOsInfo::hostOs())) .arg(osTypeToString(HostOsInfo::hostOs()))
.arg(QSysInfo::productVersion()) .arg(QSysInfo::productVersion())
@@ -444,6 +449,7 @@ QLabel *tfLabel(const TextFormat &tf, bool singleLine)
label->setFixedHeight(tf.lineHeight()); label->setFixedHeight(tf.lineHeight());
label->setFont(tf.font()); label->setFont(tf.font());
label->setAlignment(Qt::Alignment(tf.drawTextFlags)); label->setAlignment(Qt::Alignment(tf.drawTextFlags));
label->setTextInteractionFlags(Qt::TextSelectableByMouse);
QPalette pal = label->palette(); QPalette pal = label->palette();
pal.setColor(QPalette::WindowText, tf.color()); pal.setColor(QPalette::WindowText, tf.color());

View File

@@ -66,10 +66,14 @@ protected:
return QVariant::fromValue( return QVariant::fromValue(
Link(m_client->serverUriToHostPath(m_item.uri()), start.line() + 1, start.character())); Link(m_client->serverUriToHostPath(m_item.uri()), start.line() + 1, start.character()));
} }
case AnnotationRole: case AnnotationRole: {
QStringList result;
if (const std::optional<QString> detail = m_item.detail()) if (const std::optional<QString> detail = m_item.detail())
return *detail; result << *detail;
return {}; if (childCount() > 0)
result << QString("[%1]").arg(childCount());
return result.isEmpty() ? QVariant() : QVariant(result.join(' '));
}
default: default:
return TreeItem::data(column, role); return TreeItem::data(column, role);
} }

View File

@@ -1,4 +1,4 @@
---@meta Layout ---@meta Gui
local gui = {} local gui = {}

View File

@@ -37,6 +37,7 @@ public:
Utils::ProcessResultData resultData() const; Utils::ProcessResultData resultData() const;
static QString transferMethodName(FileTransferMethod method); static QString transferMethodName(FileTransferMethod method);
QString transferMethodName() const { return transferMethodName(transferMethod()); }
signals: signals:
void progress(const QString &progressMessage); void progress(const QString &progressMessage);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 611 B

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 B

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 760 B

After

Width:  |  Height:  |  Size: 594 B

View File

@@ -572,14 +572,15 @@ static QStringList environmentTemplatesPaths()
} }
static bool s_searchPathsInitialized = false; static bool s_searchPathsInitialized = false;
Q_GLOBAL_STATIC(FilePath, s_installedWizardsPath, {Core::ICore::resourcePath(WIZARD_PATH)})
Q_GLOBAL_STATIC(FilePaths, s_additionalWizardPaths)
FilePaths &JsonWizardFactory::searchPaths() FilePaths &JsonWizardFactory::searchPaths()
{ {
static FilePaths m_searchPaths; static FilePaths m_searchPaths;
if (!s_searchPathsInitialized) { if (!s_searchPathsInitialized) {
s_searchPathsInitialized = true; s_searchPathsInitialized = true;
m_searchPaths = {Core::ICore::userResourcePath(WIZARD_PATH), m_searchPaths = {Core::ICore::userResourcePath(WIZARD_PATH), *s_installedWizardsPath};
Core::ICore::resourcePath(WIZARD_PATH)};
for (const QString &environmentTemplateDirName : environmentTemplatesPaths()) for (const QString &environmentTemplateDirName : environmentTemplatesPaths())
m_searchPaths << FilePath::fromString(environmentTemplateDirName); m_searchPaths << FilePath::fromString(environmentTemplateDirName);
m_searchPaths << Utils::transform( m_searchPaths << Utils::transform(
@@ -598,6 +599,7 @@ FilePaths &JsonWizardFactory::searchPaths()
} }
} }
} }
m_searchPaths += *s_additionalWizardPaths;
} }
return m_searchPaths; return m_searchPaths;
@@ -610,12 +612,16 @@ void JsonWizardFactory::resetSearchPaths()
void JsonWizardFactory::addWizardPath(const FilePath &path) void JsonWizardFactory::addWizardPath(const FilePath &path)
{ {
searchPaths().append(path); s_additionalWizardPaths->append(path);
} }
void JsonWizardFactory::clearWizardPaths() /*!
\internal
*/
void JsonWizardFactory::setInstalledWizardsPath(const Utils::FilePath &path)
{ {
searchPaths().clear(); *s_installedWizardsPath = path;
resetSearchPaths();
} }
void JsonWizardFactory::setVerbose(int level) void JsonWizardFactory::setVerbose(int level)

View File

@@ -27,7 +27,6 @@ class PROJECTEXPLORER_EXPORT JsonWizardFactory : public Core::IWizardFactory
public: public:
// Add search paths for wizard.json files. All subdirs are going to be checked. // Add search paths for wizard.json files. All subdirs are going to be checked.
static void addWizardPath(const Utils::FilePath &path); static void addWizardPath(const Utils::FilePath &path);
static void clearWizardPaths();
// actual interface of the wizard factory: // actual interface of the wizard factory:
class Generator { class Generator {
@@ -59,6 +58,9 @@ public:
virtual std::pair<int, QStringList> screenSizeInfoFromPage(const QString &pageType) const; virtual std::pair<int, QStringList> screenSizeInfoFromPage(const QString &pageType) const;
// internal
static void setInstalledWizardsPath(const Utils::FilePath &path);
private: private:
Utils::Wizard *runWizardImpl(const Utils::FilePath &path, QWidget *parent, Utils::Id platform, Utils::Wizard *runWizardImpl(const Utils::FilePath &path, QWidget *parent, Utils::Id platform,
const QVariantMap &variables, bool showWizard = true) override; const QVariantMap &variables, bool showWizard = true) override;

View File

@@ -161,14 +161,10 @@ void ExampleSetModel::recreateModel(const QtVersions &qtVersionsIn)
// Sort by Qt version, example sets not associated to Qt last // Sort by Qt version, example sets not associated to Qt last
Utils::sort(items, [](QStandardItem *a, QStandardItem *b) { Utils::sort(items, [](QStandardItem *a, QStandardItem *b) {
const QVersionNumber versionB = b->data(kVersionRole).value<QVersionNumber>(); const QVersionNumber versionB = b->data(kVersionRole).value<QVersionNumber>();
if (versionB.isNull())
return true;
const QVersionNumber versionA = a->data(kVersionRole).value<QVersionNumber>(); const QVersionNumber versionA = a->data(kVersionRole).value<QVersionNumber>();
if (versionA.isNull()) if (versionA != versionB)
return false; return versionA < versionB;
if (versionA == versionB) return a->data(Qt::DisplayRole).toString() < b->data(Qt::DisplayRole).toString();
return a->data(Qt::DisplayRole).toString() < b->data(Qt::DisplayRole).toString();
return versionA < versionB;
}); });
for (QStandardItem *item : std::as_const(items)) for (QStandardItem *item : std::as_const(items))

View File

@@ -176,12 +176,16 @@ GroupItem GenericDeployStep::transferTask(const Storage<FilesToTransfer> &storag
const auto onError = [this](const FileTransfer &transfer) { const auto onError = [this](const FileTransfer &transfer) {
const ProcessResultData result = transfer.resultData(); const ProcessResultData result = transfer.resultData();
if (result.m_error == QProcess::FailedToStart) { if (result.m_error == QProcess::FailedToStart) {
addErrorMessage(Tr::tr("rsync failed to start: %1").arg(result.m_errorString)); addErrorMessage(Tr::tr("%1 failed to start: %2")
.arg(transfer.transferMethodName(), result.m_errorString));
} else if (result.m_exitStatus == QProcess::CrashExit) { } else if (result.m_exitStatus == QProcess::CrashExit) {
addErrorMessage(Tr::tr("rsync crashed.")); addErrorMessage(Tr::tr("%1 crashed.").arg(transfer.transferMethodName()));
} else if (result.m_exitCode != 0) { } else if (result.m_exitCode != 0) {
addErrorMessage(Tr::tr("rsync failed with exit code %1.").arg(result.m_exitCode) addErrorMessage(
+ "\n" + result.m_errorString); Tr::tr("%1 failed with exit code %2.")
.arg(transfer.transferMethodName())
.arg(result.m_exitCode)
+ "\n" + result.m_errorString);
} }
}; };
return FileTransferTask(onSetup, onError, CallDoneIf::Error); return FileTransferTask(onSetup, onError, CallDoneIf::Error);

View File

@@ -27,11 +27,6 @@ using namespace Utils;
namespace RemoteLinux { namespace RemoteLinux {
namespace Internal { namespace Internal {
struct TransferStorage
{
bool useGenericCopy = false;
};
class GenericLinuxDeviceTesterPrivate class GenericLinuxDeviceTesterPrivate
{ {
public: public:
@@ -43,8 +38,7 @@ public:
GroupItem echoTask(const QString &contents) const; GroupItem echoTask(const QString &contents) const;
GroupItem unameTask() const; GroupItem unameTask() const;
GroupItem gathererTask() const; GroupItem gathererTask() const;
GroupItem transferTask(FileTransferMethod method, GroupItem transferTask(FileTransferMethod method) const;
const Storage<TransferStorage> &storage) const;
GroupItem transferTasks() const; GroupItem transferTasks() const;
GroupItem commandTasks() const; GroupItem commandTasks() const;
@@ -192,8 +186,7 @@ GroupItem GenericLinuxDeviceTesterPrivate::gathererTask() const
}; };
} }
GroupItem GenericLinuxDeviceTesterPrivate::transferTask(FileTransferMethod method, GroupItem GenericLinuxDeviceTesterPrivate::transferTask(FileTransferMethod method) const
const Storage<TransferStorage> &storage) const
{ {
const auto onSetup = [this, method](FileTransfer &transfer) { const auto onSetup = [this, method](FileTransfer &transfer) {
emit q->progressMessage(Tr::tr("Checking whether \"%1\" works...") emit q->progressMessage(Tr::tr("Checking whether \"%1\" works...")
@@ -201,7 +194,7 @@ GroupItem GenericLinuxDeviceTesterPrivate::transferTask(FileTransferMethod metho
transfer.setTransferMethod(method); transfer.setTransferMethod(method);
transfer.setTestDevice(m_device); transfer.setTestDevice(m_device);
}; };
const auto onDone = [this, method, storage](const FileTransfer &transfer, DoneWith result) { const auto onDone = [this, method](const FileTransfer &transfer, DoneWith result) {
const QString methodName = FileTransfer::transferMethodName(method); const QString methodName = FileTransfer::transferMethodName(method);
if (result == DoneWith::Success) { if (result == DoneWith::Success) {
emit q->progressMessage(Tr::tr("\"%1\" is functional.\n").arg(methodName)); emit q->progressMessage(Tr::tr("\"%1\" is functional.\n").arg(methodName));
@@ -209,8 +202,6 @@ GroupItem GenericLinuxDeviceTesterPrivate::transferTask(FileTransferMethod metho
m_device->setExtraData(Constants::SUPPORTS_RSYNC, true); m_device->setExtraData(Constants::SUPPORTS_RSYNC, true);
else if (method == FileTransferMethod::Sftp) else if (method == FileTransferMethod::Sftp)
m_device->setExtraData(Constants::SUPPORTS_SFTP, true); m_device->setExtraData(Constants::SUPPORTS_SFTP, true);
else
storage->useGenericCopy = true;
return; return;
} }
const ProcessResultData resultData = transfer.resultData(); const ProcessResultData resultData = transfer.resultData();
@@ -251,13 +242,11 @@ GroupItem GenericLinuxDeviceTesterPrivate::transferTask(FileTransferMethod metho
GroupItem GenericLinuxDeviceTesterPrivate::transferTasks() const GroupItem GenericLinuxDeviceTesterPrivate::transferTasks() const
{ {
Storage<TransferStorage> storage;
return Group { return Group {
continueOnSuccess, continueOnSuccess,
storage, transferTask(FileTransferMethod::GenericCopy),
transferTask(FileTransferMethod::GenericCopy, storage), transferTask(FileTransferMethod::Sftp),
transferTask(FileTransferMethod::Sftp, storage), transferTask(FileTransferMethod::Rsync),
transferTask(FileTransferMethod::Rsync, storage),
onGroupDone([this] { onGroupDone([this] {
emit q->errorMessage(Tr::tr("Deployment to this device will not work out of the box.") emit q->errorMessage(Tr::tr("Deployment to this device will not work out of the box.")
+ "\n"); + "\n");

View File

@@ -609,8 +609,7 @@ void StudioWelcomePlugin::extensionsInitialized()
// Enable QDS new project dialog and QDS wizards // Enable QDS new project dialog and QDS wizards
if (Core::ICore::isQtDesignStudio()) { if (Core::ICore::isQtDesignStudio()) {
ProjectExplorer::JsonWizardFactory::clearWizardPaths(); ProjectExplorer::JsonWizardFactory::setInstalledWizardsPath(
ProjectExplorer::JsonWizardFactory::addWizardPath(
Core::ICore::resourcePath("qmldesigner/studio_templates")); Core::ICore::resourcePath("qmldesigner/studio_templates"));
Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); }); Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); });

View File

@@ -3087,15 +3087,21 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
if (ro || !isPrintableText(eventText)) { if (ro || !isPrintableText(eventText)) {
QTextCursor::MoveOperation blockSelectionOperation = QTextCursor::NoMove; QTextCursor::MoveOperation blockSelectionOperation = QTextCursor::NoMove;
if (e->modifiers() == (Qt::AltModifier | Qt::ShiftModifier) && !Utils::HostOsInfo::isMacHost()) { if (e->modifiers() == (Qt::AltModifier | Qt::ShiftModifier)
if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToNextLine)) && !Utils::HostOsInfo::isMacHost()) {
if (MultiTextCursor::multiCursorEvent(
e, QKeySequence::MoveToNextLine, Qt::ShiftModifier)) {
blockSelectionOperation = QTextCursor::Down; blockSelectionOperation = QTextCursor::Down;
else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToPreviousLine)) } else if (MultiTextCursor::multiCursorEvent(
e, QKeySequence::MoveToPreviousLine, Qt::ShiftModifier)) {
blockSelectionOperation = QTextCursor::Up; blockSelectionOperation = QTextCursor::Up;
else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToNextChar)) } else if (MultiTextCursor::multiCursorEvent(
e, QKeySequence::MoveToNextChar, Qt::ShiftModifier)) {
blockSelectionOperation = QTextCursor::NextCharacter; blockSelectionOperation = QTextCursor::NextCharacter;
else if (MultiTextCursor::multiCursorAddEvent(e, QKeySequence::MoveToPreviousChar)) } else if (MultiTextCursor::multiCursorEvent(
e, QKeySequence::MoveToPreviousChar, Qt::ShiftModifier)) {
blockSelectionOperation = QTextCursor::PreviousCharacter; blockSelectionOperation = QTextCursor::PreviousCharacter;
}
} }
if (blockSelectionOperation != QTextCursor::NoMove) { if (blockSelectionOperation != QTextCursor::NoMove) {
@@ -7431,6 +7437,25 @@ void TextEditorWidgetPrivate::handleBackspaceKey()
QTC_ASSERT(!q->multiTextCursor().hasSelection(), return); QTC_ASSERT(!q->multiTextCursor().hasSelection(), return);
MultiTextCursor cursor = m_cursors; MultiTextCursor cursor = m_cursors;
cursor.beginEditBlock(); cursor.beginEditBlock();
const TabSettings tabSettings = m_document->tabSettings();
const TypingSettings &typingSettings = m_document->typingSettings();
auto behavior = typingSettings.m_smartBackspaceBehavior;
if (cursor.hasMultipleCursors()) {
if (behavior == TypingSettings::BackspaceFollowsPreviousIndents) {
behavior = TypingSettings::BackspaceNeverIndents;
} else if (behavior == TypingSettings::BackspaceUnindents) {
for (QTextCursor &c : cursor) {
if (c.positionInBlock() == 0
|| c.positionInBlock() > TabSettings::firstNonSpace(c.block().text())) {
behavior = TypingSettings::BackspaceNeverIndents;
break;
}
}
}
}
for (QTextCursor &c : cursor) { for (QTextCursor &c : cursor) {
const int pos = c.position(); const int pos = c.position();
if (!pos) if (!pos)
@@ -7443,9 +7468,6 @@ void TextEditorWidgetPrivate::handleBackspaceKey()
cursorWithinSnippet = snippetCheckCursor(snippetCursor); cursorWithinSnippet = snippetCheckCursor(snippetCursor);
} }
const TabSettings tabSettings = m_document->tabSettings();
const TypingSettings &typingSettings = m_document->typingSettings();
if (typingSettings.m_autoIndent && !m_autoCompleteHighlightPos.isEmpty() if (typingSettings.m_autoIndent && !m_autoCompleteHighlightPos.isEmpty()
&& (m_autoCompleteHighlightPos.last() == c) && m_removeAutoCompletedText && (m_autoCompleteHighlightPos.last() == c) && m_removeAutoCompletedText
&& m_autoCompleter->autoBackspace(c)) { && m_autoCompleter->autoBackspace(c)) {
@@ -7453,12 +7475,12 @@ void TextEditorWidgetPrivate::handleBackspaceKey()
} }
bool handled = false; bool handled = false;
if (typingSettings.m_smartBackspaceBehavior == TypingSettings::BackspaceNeverIndents) { if (behavior == TypingSettings::BackspaceNeverIndents) {
if (cursorWithinSnippet) if (cursorWithinSnippet)
c.beginEditBlock(); c.beginEditBlock();
c.deletePreviousChar(); c.deletePreviousChar();
handled = true; handled = true;
} else if (typingSettings.m_smartBackspaceBehavior } else if (behavior
== TypingSettings::BackspaceFollowsPreviousIndents) { == TypingSettings::BackspaceFollowsPreviousIndents) {
QTextBlock currentBlock = c.block(); QTextBlock currentBlock = c.block();
int positionInBlock = pos - currentBlock.position(); int positionInBlock = pos - currentBlock.position();
@@ -7493,7 +7515,7 @@ void TextEditorWidgetPrivate::handleBackspaceKey()
} }
} }
} }
} else if (typingSettings.m_smartBackspaceBehavior == TypingSettings::BackspaceUnindents) { } else if (behavior == TypingSettings::BackspaceUnindents) {
if (c.positionInBlock() == 0 if (c.positionInBlock() == 0
|| c.positionInBlock() > TabSettings::firstNonSpace(c.block().text())) { || c.positionInBlock() > TabSettings::firstNonSpace(c.block().text())) {
if (cursorWithinSnippet) if (cursorWithinSnippet)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 B

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 285 B

After

Width:  |  Height:  |  Size: 273 B

View File

@@ -8727,17 +8727,10 @@
width="100%" width="100%"
height="100%" height="100%"
style="stroke-width:0.88039" /> style="stroke-width:0.88039" />
<g <path
id="g34266" id="path4"
style="stroke:#000000;stroke-linecap:round;stroke-linejoin:round;fill:none"> style="fill:none;stroke:#000000;stroke-width:2;stroke-linejoin:round"
<path d="m 55,64 v -7 h 6 v 7 M 50,52.5 V 64 H 66 V 52.5 l -8,-6 z" />
id="path34132"
d="M 51,54 V 64 H 65 V 54 m -16,-2 9,-6 9,6"
style="stroke-width:2" />
<path
id="path34224"
d="m 60.5,58.5 h 1 v 1 h -1 z m 0,-3 h 1 v 1 h -1 z m -3,3 h 1 v 1 h -1 z m 0,-3 h 1 v 1 h -1 z m -3,3 h 1 v 1 h -1 z m 0,-3 h 1 v 1 h -1 z" />
</g>
</g> </g>
<g <g
transform="translate(-55,264)" transform="translate(-55,264)"
@@ -8757,6 +8750,20 @@
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round" style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round"
d="m 100,63 h 16 m -16,-4 h 12 m -12,-4 h 16 m -16,-4 h 12 m -12,-4 h 16" /> d="m 100,63 h 16 m -16,-4 h 12 m -12,-4 h 16 m -16,-4 h 12 m -12,-4 h 16" />
</g> </g>
<g
id="mode_design_pen">
<rect
style="fill:#ffffff"
id="rect17"
width="13"
height="21"
x="83"
y="280" />
<path
id="path47960"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round"
d="M 91,290.5 A 1.5,1.5 0 0 1 89.5,292 1.5,1.5 0 0 1 88,290.5 1.5,1.5 0 0 1 89.5,289 1.5,1.5 0 0 1 91,290.5 Z M 89.5,281 v 8 m -3.5,6 c 7,0 7,0 7,0 m -4.5,-14 h 2 l 4,10 -1.5,4 1.5,3 h -10 l 1.5,-3 -1.5,-4 z" />
</g>
<g <g
transform="translate(-69,264)" transform="translate(-69,264)"
style="display:inline" style="display:inline"
@@ -8770,16 +8777,12 @@
id="use5913-0" id="use5913-0"
width="100%" width="100%"
height="100%" /> height="100%" />
<g <use
id="g49500" x="0"
inkscape:transform-center-y="0.70710678" y="0"
transform="rotate(-45,157.5,54.5)" xlink:href="#mode_design_pen"
inkscape:transform-center-x="-0.70710678"> id="use18"
<path transform="rotate(-135,75.244119,159.91674)" />
id="path47960"
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round"
d="M 159,54.5 A 1.5,1.5 0 0 1 157.5,56 1.5,1.5 0 0 1 156,54.5 1.5,1.5 0 0 1 157.5,53 1.5,1.5 0 0 1 159,54.5 Z M 157.5,45 v 8 m -3.5,6 c 7,0 7,0 7,0 m -4.5,-14 h 2 l 4,10 -1.5,4 1.5,3 h -10 l 1.5,-3 -1.5,-4 z" />
</g>
</g> </g>
<g <g
transform="translate(-83,264)" transform="translate(-83,264)"
@@ -8809,6 +8812,14 @@
ry="5" /> ry="5" />
</g> </g>
</g> </g>
<g
id="mode_project_wrench">
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linejoin:round"
d="m 159,277 v 5.5 l 0.5,0.5 h 3 l 0.5,-0.5 V 277 c 0.5,0 4.0272,1.45336 4,5.5 -0.0269,3.99991 -4,5.5 -4,5.5 v 9 c 0,1.5 -1,2 -2,2 -1,0 -2,-0.5 -2,-2 v -9 c 0,0 -3.99599,-1.5 -4,-5.5 -0.004,-4.12282 3.5,-5.5 4,-5.5 z"
id="path8"
sodipodi:nodetypes="ccccccscssscsc" />
</g>
<g <g
transform="translate(-97,264)" transform="translate(-97,264)"
style="display:inline" style="display:inline"
@@ -8822,32 +8833,12 @@
id="use5913-0-8-3" id="use5913-0-8-3"
width="100%" width="100%"
height="100%" /> height="100%" />
<circle <use
style="fill:none;stroke:#000000;stroke-width:2" x="0"
id="path86372" y="0"
cx="258" xlink:href="#mode_project_wrench"
cy="55" id="use17"
r="9" /> transform="rotate(45,489.04885,287.88225)" />
<g
id="g88204"
transform="rotate(45,258,55)">
<path
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round"
d="m 258,60.5 v -5"
id="path86584"
sodipodi:nodetypes="cc" />
<circle
style="fill:#000000"
id="path86725"
cx="258"
cy="52.5"
r="3.5" />
<path
style="fill:none;stroke:#ffffff"
d="M 258,52 V 48"
id="path87283"
sodipodi:nodetypes="cc" />
</g>
</g> </g>
<g <g
transform="translate(-162,264)" transform="translate(-162,264)"
@@ -9063,6 +9054,31 @@
d="m 765,51 6,6 -6,7 z" d="m 765,51 6,6 -6,7 z"
id="path34590" /> id="path34590" />
</g> </g>
<g
id="build_hammer"
transform="translate(-667,327)">
<rect
style="fill:#ffffff"
id="rect11"
width="20"
height="22"
x="854"
y="47" />
<rect
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round"
id="rect8"
width="4"
height="15"
x="862"
y="53"
ry="1"
rx="1" />
<path
style="fill:none;stroke:#000000;stroke-width:2"
d="m 870,48 h -8.5 c -2,0 -4,3 -5,5 H 870 Z"
id="path11"
sodipodi:nodetypes="csccc" />
</g>
<g <g
transform="translate(-664,297)" transform="translate(-664,297)"
style="display:inline" style="display:inline"
@@ -9076,18 +9092,12 @@
id="use5913-0-8-1-89" id="use5913-0-8-1-89"
width="100%" width="100%"
height="100%" /> height="100%" />
<g <use
id="g29289" x="0"
transform="rotate(30,861.61602,58.5)"> y="0"
<path xlink:href="#build_hammer"
id="path25494" id="use20"
style="fill:#ffffff;stroke:#000000;stroke-width:4;stroke-linejoin:round;paint-order:markers stroke fill" transform="rotate(45,922.51682,1023.5188)" />
d="m 858,52 h 6 v -1 h -6 m 2,6 h 1 v 10 h -1 z" />
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round"
d="m 858,50 c -1.5,0 -3.5,1.5 -3.5,3 h 3.5"
id="path26814" />
</g>
</g> </g>
<g <g
transform="translate(-247.5,256)" transform="translate(-247.5,256)"

Before

Width:  |  Height:  |  Size: 374 KiB

After

Width:  |  Height:  |  Size: 374 KiB