Merge remote-tracking branch 'origin/4.4'

Change-Id: Id525d68a899f2db14c2d52c200a3a2a8a4e81590
This commit is contained in:
Eike Ziller
2017-08-24 13:23:04 +02:00
16 changed files with 213 additions and 66 deletions

View File

@@ -195,6 +195,31 @@
save space. save space.
\endlist \endlist
\section2 Hightlighting Parts of the Screen
You can use number icons in screenshots to highlight parts of the screenshot
(instead of using red arrows or borders, or something similar). You can then
refer to the numbers in text. For and example, see the
\l{http://doc.qt.io/qt-5/topics-app-development.html}{Development Tools}
topic in the Qt reference documentation.
This improves the consistency of the look and feel of Qt documentation,
and eliminates the need to describe parts of the UI in the text, because
you can just insert the number of the element you are referring to in
brackets.
You can find a set of images that show the numbers from 1 to 10 in the
\c doc\images\numbers directory (or in the \c qtdoc module sources in
\c doc\images\numbers).
To use the numbers:
\list
\li Take a screenshot as described above.
\li After resizing the screenshot, copy-paste the number images on
the screenshot to the places that you want to refer to from text.
\endlist
\section2 Optimizing Images \section2 Optimizing Images
Save images in the PNG format in the \QC project folder in the Save images in the PNG format in the \QC project folder in the
@@ -241,6 +266,18 @@
You can also see the sizes of the initial and optimized image. You can also see the sizes of the initial and optimized image.
\section3 Using OptiPNG
Download and install \l{https://sourceforge.net/projects/optipng/}{OptiPNG}.
OptiPNG is a command-line tool that you can invoke from the \QC project
folder (or any folder that contains your project). To optimize a screenshot,
enter the following command (here, from the \QC project folder):
\code
optipng -o 7 -strip all doc/images/<screenshot_name>
\endcode
\section1 Building Documentation \section1 Building Documentation
You use QDoc to build the documentation. Build the documentation from time You use QDoc to build the documentation. Build the documentation from time

View File

@@ -269,4 +269,71 @@ QTCREATOR_UTILS_EXPORT bool readMultiLineString(const QJsonValue &value, QString
return true; return true;
} }
QTCREATOR_UTILS_EXPORT int parseUsedPortFromNetstatOutput(const QByteArray &line)
{
const QByteArray trimmed = line.trimmed();
int base = 0;
QByteArray portString;
if (trimmed.startsWith("TCP") || trimmed.startsWith("UDP")) {
// Windows. Expected output is something like
//
// Active Connections
//
// Proto Local Address Foreign Address State
// TCP 0.0.0.0:80 0.0.0.0:0 LISTENING
// TCP 0.0.0.0:113 0.0.0.0:0 LISTENING
// [...]
// TCP 10.9.78.4:14714 0.0.0.0:0 LISTENING
// TCP 10.9.78.4:50233 12.13.135.180:993 ESTABLISHED
// [...]
// TCP [::]:445 [::]:0 LISTENING
// TCP 192.168.0.80:51905 169.55.74.50:443 ESTABLISHED
// UDP [fe80::880a:2932:8dff:a858%6]:1900 *:*
const int firstBracketPos = trimmed.indexOf('[');
int colonPos = -1;
if (firstBracketPos == -1) {
colonPos = trimmed.indexOf(':'); // IPv4
} else {
// jump over host part
const int secondBracketPos = trimmed.indexOf(']', firstBracketPos + 1);
colonPos = trimmed.indexOf(':', secondBracketPos);
}
const int firstDigitPos = colonPos + 1;
const int spacePos = trimmed.indexOf(' ', firstDigitPos);
if (spacePos < 0)
return -1;
const int len = spacePos - firstDigitPos;
base = 10;
portString = trimmed.mid(firstDigitPos, len);
} else {
// Expected output on Linux something like
//
// sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt ...
// 0: 00000000:2805 00000000:0000 0A 00000000:00000000 00:00000000 00000000 ...
//
const int firstColonPos = trimmed.indexOf(':');
if (firstColonPos < 0)
return -1;
const int secondColonPos = trimmed.indexOf(':', firstColonPos + 1);
if (secondColonPos < 0)
return -1;
const int spacePos = trimmed.indexOf(' ', secondColonPos + 1);
if (spacePos < 0)
return -1;
const int len = spacePos - secondColonPos - 1;
base = 16;
portString = trimmed.mid(secondColonPos + 1, len);
}
bool ok = true;
const int port = portString.toInt(&ok, base);
if (!ok) {
qWarning("%s: Unexpected string '%s' is not a port. Tried to read from '%s'",
Q_FUNC_INFO, line.data(), portString.data());
return -1;
}
return port;
}
} // namespace Utils } // namespace Utils

View File

@@ -79,4 +79,6 @@ private:
QTCREATOR_UTILS_EXPORT void expandMacros(QString *str, AbstractMacroExpander *mx); QTCREATOR_UTILS_EXPORT void expandMacros(QString *str, AbstractMacroExpander *mx);
QTCREATOR_UTILS_EXPORT QString expandMacros(const QString &str, AbstractMacroExpander *mx); QTCREATOR_UTILS_EXPORT QString expandMacros(const QString &str, AbstractMacroExpander *mx);
QTCREATOR_UTILS_EXPORT int parseUsedPortFromNetstatOutput(const QByteArray &line);
} // namespace Utils } // namespace Utils

View File

@@ -164,7 +164,7 @@ bool OpenOcdGdbServerProvider::isValid() const
} }
if (m == StartupOnNetwork || m == StartupOnPipe) { if (m == StartupOnNetwork || m == StartupOnPipe) {
if (m_executableFile.isEmpty() || m_configurationFile.isEmpty()) if (m_executableFile.isEmpty())
return false; return false;
} }

View File

@@ -98,6 +98,8 @@ void CppUseSelectionsUpdater::update(CallType callType)
const int startRevision = cppEditorDocument->document()->revision(); const int startRevision = cppEditorDocument->document()->revision();
QFuture<CursorInfo> future = cppEditorDocument->cursorInfo(params); QFuture<CursorInfo> future = cppEditorDocument->cursorInfo(params);
if (future.isCanceled())
return;
// QFuture::waitForFinished seems to block completely, not even // QFuture::waitForFinished seems to block completely, not even
// allowing to process events from QLocalSocket. // allowing to process events from QLocalSocket.

View File

@@ -358,6 +358,9 @@ QFuture<CursorInfo> BuiltinCursorInfo::run(const CursorInfoParams &cursorInfoPar
CppTools::SemanticInfo::LocalUseMap CppTools::SemanticInfo::LocalUseMap
BuiltinCursorInfo::findLocalUses(const Document::Ptr &document, int line, int column) BuiltinCursorInfo::findLocalUses(const Document::Ptr &document, int line, int column)
{ {
if (!document || !document->translationUnit() || !document->translationUnit()->ast())
return SemanticInfo::LocalUseMap();
AST *ast = document->translationUnit()->ast(); AST *ast = document->translationUnit()->ast();
FunctionDefinitionUnderCursor functionDefinitionUnderCursor(document->translationUnit()); FunctionDefinitionUnderCursor functionDefinitionUnderCursor(document->translationUnit());
DeclarationAST *declaration = functionDefinitionUnderCursor(ast, DeclarationAST *declaration = functionDefinitionUnderCursor(ast,

View File

@@ -2490,6 +2490,8 @@ void DebuggerPluginPrivate::cleanupViews()
bool keepIt = true; bool keepIt = true;
if (document->isModified()) if (document->isModified())
keepIt = true; keepIt = true;
else if (document->filePath().toString().contains("qeventdispatcher"))
keepIt = false;
else if (isMemory) else if (isMemory)
keepIt = !closeMemory; keepIt = !closeMemory;
else else

View File

@@ -85,6 +85,11 @@ HelpViewer::HelpViewer(QWidget *parent)
{ {
} }
HelpViewer::~HelpViewer()
{
restoreOverrideCursor();
}
void HelpViewer::setActionVisible(Action action, bool visible) void HelpViewer::setActionVisible(Action action, bool visible)
{ {
if (visible) if (visible)
@@ -156,16 +161,25 @@ void HelpViewer::home()
void HelpViewer::slotLoadStarted() void HelpViewer::slotLoadStarted()
{ {
++m_loadOverrideStack;
QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
} }
void HelpViewer::slotLoadFinished() void HelpViewer::slotLoadFinished()
{ {
QGuiApplication::restoreOverrideCursor(); restoreOverrideCursor();
emit sourceChanged(source()); emit sourceChanged(source());
emit loadFinished(); emit loadFinished();
} }
void HelpViewer::restoreOverrideCursor()
{
while (m_loadOverrideStack > 0) {
--m_loadOverrideStack;
QGuiApplication::restoreOverrideCursor();
}
}
bool HelpViewer::handleForwardBackwardMouseButtons(QMouseEvent *event) bool HelpViewer::handleForwardBackwardMouseButtons(QMouseEvent *event)
{ {
if (event->button() == Qt::XButton1) { if (event->button() == Qt::XButton1) {

View File

@@ -49,7 +49,7 @@ public:
Q_DECLARE_FLAGS(Actions, Action) Q_DECLARE_FLAGS(Actions, Action)
explicit HelpViewer(QWidget *parent = 0); explicit HelpViewer(QWidget *parent = 0);
~HelpViewer() { } ~HelpViewer();
virtual QFont viewerFont() const = 0; virtual QFont viewerFont() const = 0;
virtual void setViewerFont(const QFont &font) = 0; virtual void setViewerFont(const QFont &font) = 0;
@@ -109,7 +109,10 @@ protected:
void slotLoadStarted(); void slotLoadStarted();
void slotLoadFinished(); void slotLoadFinished();
void restoreOverrideCursor();
Actions m_visibleActions = 0; Actions m_visibleActions = 0;
int m_loadOverrideStack = 0;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -110,8 +110,8 @@ private:
protected: protected:
void mouseMoveEvent(QMouseEvent *ev) void mouseMoveEvent(QMouseEvent *ev)
{ {
int line = cursorForPosition(ev->pos()).block().blockNumber(); const int line = cursorForPosition(ev->pos()).block().blockNumber();
if (m_taskids.value(line, 0)) if (m_taskids.contains(line) && m_mousePressButton == Qt::NoButton)
viewport()->setCursor(Qt::PointingHandCursor); viewport()->setCursor(Qt::PointingHandCursor);
else else
viewport()->setCursor(Qt::IBeamCursor); viewport()->setCursor(Qt::IBeamCursor);
@@ -121,23 +121,27 @@ protected:
void mousePressEvent(QMouseEvent *ev) void mousePressEvent(QMouseEvent *ev)
{ {
m_mousePressPosition = ev->pos(); m_mousePressPosition = ev->pos();
m_mousePressButton = ev->button();
QPlainTextEdit::mousePressEvent(ev); QPlainTextEdit::mousePressEvent(ev);
} }
void mouseReleaseEvent(QMouseEvent *ev) void mouseReleaseEvent(QMouseEvent *ev)
{ {
if ((m_mousePressPosition - ev->pos()).manhattanLength() < 4) { if ((m_mousePressPosition - ev->pos()).manhattanLength() < 4
&& m_mousePressButton == Qt::LeftButton) {
int line = cursorForPosition(ev->pos()).block().blockNumber(); int line = cursorForPosition(ev->pos()).block().blockNumber();
if (unsigned taskid = m_taskids.value(line, 0)) if (unsigned taskid = m_taskids.value(line, 0))
TaskHub::showTaskInEditor(taskid); TaskHub::showTaskInEditor(taskid);
} }
m_mousePressButton = Qt::NoButton;
QPlainTextEdit::mouseReleaseEvent(ev); QPlainTextEdit::mouseReleaseEvent(ev);
} }
private: private:
QHash<int, unsigned int> m_taskids; //Map blocknumber to taskId QHash<int, unsigned int> m_taskids; //Map blocknumber to taskId
QPoint m_mousePressPosition; QPoint m_mousePressPosition;
Qt::MouseButton m_mousePressButton = Qt::NoButton;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -39,6 +39,7 @@
#include <utils/environment.h> #include <utils/environment.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/portlist.h> #include <utils/portlist.h>
#include <utils/stringutils.h>
#include <QCoreApplication> #include <QCoreApplication>
@@ -168,65 +169,10 @@ class DesktopPortsGatheringMethod : public PortsGatheringMethod
{ {
QList<Utils::Port> ports; QList<Utils::Port> ports;
const QList<QByteArray> lines = output.split('\n'); const QList<QByteArray> lines = output.split('\n');
if (HostOsInfo::isWindowsHost()) { for (const QByteArray &line : lines) {
// Expected output is something like const Port port(Utils::parseUsedPortFromNetstatOutput(line));
// if (port.isValid() && !ports.contains(port))
// Active Connections ports.append(port);
//
// Proto Local Address Foreign Address State
// TCP 0.0.0.0:80 0.0.0.0:0 LISTENING
// TCP 0.0.0.0:113 0.0.0.0:0 LISTENING
// [...]
// TCP 10.9.78.4:14714 0.0.0.0:0 LISTENING
// TCP 10.9.78.4:50233 12.13.135.180:993 ESTABLISHED
for (const QByteArray &line : lines) {
const QByteArray trimmed = line.trimmed();
if (!trimmed.startsWith("TCP"))
continue;
int colonPos = trimmed.indexOf(':');
if (colonPos < 0)
continue;
int spacePos = trimmed.indexOf(':', colonPos + 1);
if (spacePos < 0)
continue;
bool ok;
int len = spacePos - colonPos - 1;
const Utils::Port port(line.mid(colonPos + 1, len).toInt(&ok, 16));
if (ok) {
if (!ports.contains(port))
ports << port;
} else {
qWarning("%s: Unexpected string '%s' is not a port.",
Q_FUNC_INFO, line.data());
}
}
} else if (HostOsInfo::isLinuxHost()) {
// Expected outpit is something like
//
// sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt ...
// 0: 00000000:2805 00000000:0000 0A 00000000:00000000 00:00000000 00000000 ...
//
for (const QByteArray &line : lines) {
int firstColonPos = line.indexOf(':');
if (firstColonPos < 0)
continue;
int secondColonPos = line.indexOf(':', firstColonPos + 1);
if (secondColonPos < 0)
continue;
int spacePos = line.indexOf(':', secondColonPos + 1);
if (spacePos < 0)
continue;
bool ok;
int len = spacePos - secondColonPos - 1;
const Utils::Port port(line.mid(secondColonPos + 1, len).toInt(&ok, 16));
if (ok) {
if (!ports.contains(port))
ports << port;
} else {
qWarning("%s: Unexpected string '%s' is not a port.",
Q_FUNC_INFO, line.data());
}
}
} }
return ports; return ports;
} }

View File

@@ -150,6 +150,11 @@ bool Document::isIntact() const
&& !d->hasParseOrReparseFailed; && !d->hasParseOrReparseFailed;
} }
bool Document::isParsed() const
{
return d->translationUnits.areAllTranslationUnitsParsed();
}
Utf8String Document::filePath() const Utf8String Document::filePath() const
{ {
checkIfNull(); checkIfNull();

View File

@@ -77,6 +77,7 @@ public:
bool isNull() const; bool isNull() const;
bool isIntact() const; bool isIntact() const;
bool isParsed() const;
Utf8String filePath() const; Utf8String filePath() const;
Utf8StringVector fileArguments() const; Utf8StringVector fileArguments() const;

View File

@@ -97,7 +97,8 @@ static bool isSuspendable(const Document &document)
{ {
return isFineDocument(document) return isFineDocument(document)
&& !document.isSuspended() && !document.isSuspended()
&& !document.isVisibleInEditor(); && !document.isVisibleInEditor()
&& document.isParsed();
} }
static bool isResumable(const Document &document) static bool isResumable(const Document &document)

View File

@@ -82,6 +82,8 @@ private slots:
void testMacroExpander(); void testMacroExpander();
void testStripAccelerator(); void testStripAccelerator();
void testStripAccelerator_data(); void testStripAccelerator_data();
void testParseUsedPortFromNetstatOutput();
void testParseUsedPortFromNetstatOutput_data();
private: private:
TestMacroExpander mx; TestMacroExpander mx;
@@ -202,6 +204,37 @@ void tst_StringUtils::testStripAccelerator_data()
QTest::newRow("Test&") << "Test"; QTest::newRow("Test&") << "Test";
} }
void tst_StringUtils::testParseUsedPortFromNetstatOutput()
{
QFETCH(QString, line);
QFETCH(int, port);
QCOMPARE(Utils::parseUsedPortFromNetstatOutput(line.toUtf8()), port);
}
void tst_StringUtils::testParseUsedPortFromNetstatOutput_data()
{
QTest::addColumn<QString>("line");
QTest::addColumn<int>("port");
QTest::newRow("Empty") << "" << -1;
// Windows netstat.
QTest::newRow("Win1") << "Active Connection" << -1;
QTest::newRow("Win2") << " Proto Local Address Foreign Address State" << -1;
QTest::newRow("Win3") << " TCP 0.0.0.0:80 0.0.0.0:0 LISTENING" << 80;
QTest::newRow("Win4") << " TCP 0.0.0.0:113 0.0.0.0:0 LISTENING" << 113;
QTest::newRow("Win5") << " TCP 10.9.78.4:14714 0.0.0.0:0 LISTENING" << 14714;
QTest::newRow("Win6") << " TCP 10.9.78.4:50233 12.13.135.180:993 ESTABLISHED" << 50233;
QTest::newRow("Win7") << " TCP [::]:445 [::]:0 LISTENING" << 445;
QTest::newRow("Win8") << " TCP 192.168.0.80:51905 169.55.74.50:443 ESTABLISHED" << 51905;
QTest::newRow("Win9") << " UDP [fe80::840a:2942:8def:abcd%6]:1900 *:* " << 1900;
// Linux
QTest::newRow("Linux1") << "sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt ..." << -1;
QTest::newRow("Linux2") << "0: 00000000:2805 00000000:0000 0A 00000000:00000000 00:00000000 00000000 ..." << 10245;
}
QTEST_MAIN(tst_StringUtils) QTEST_MAIN(tst_StringUtils)
#include "tst_stringutils.moc" #include "tst_stringutils.moc"

View File

@@ -73,6 +73,7 @@ protected:
Document getDocument(const Utf8String &filePath); Document getDocument(const Utf8String &filePath);
void categorizeDocuments(int hotDocumentsSize); void categorizeDocuments(int hotDocumentsSize);
SuspendResumeJobs createSuspendResumeJobs(int hotDocumentsSize = -1); SuspendResumeJobs createSuspendResumeJobs(int hotDocumentsSize = -1);
static void setParsed(Document &document);
protected: protected:
ClangBackEnd::ProjectParts projects; ClangBackEnd::ProjectParts projects;
@@ -176,6 +177,8 @@ TEST_F(DocumentSuspenderResumer, CreateSuspendJobForInvisible)
Document document = documents.create({fileContainer1})[0]; Document document = documents.create({fileContainer1})[0];
document.setIsSuspended(false); document.setIsSuspended(false);
document.setIsVisibleInEditor(false, Clock::now()); document.setIsVisibleInEditor(false, Clock::now());
setParsed(document);
const SuspendResumeJobs expectedJobs = { const SuspendResumeJobs expectedJobs = {
{document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed} {document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed}
}; };
@@ -196,12 +199,24 @@ TEST_F(DocumentSuspenderResumer, DoNotCreateSuspendJobForVisible)
ASSERT_THAT(jobs, ContainerEq(SuspendResumeJobs())); ASSERT_THAT(jobs, ContainerEq(SuspendResumeJobs()));
} }
TEST_F(DocumentSuspenderResumer, DoNotCreateSuspendJobForUnparsed)
{
Document document = documents.create({fileContainer1})[0];
document.setIsSuspended(false);
document.setIsVisibleInEditor(true, Clock::now());
const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 0);
ASSERT_THAT(jobs, ContainerEq(SuspendResumeJobs()));
}
TEST_F(DocumentSuspenderResumer, CreateSuspendJobsForDocumentWithSupportiveTranslationUnit) TEST_F(DocumentSuspenderResumer, CreateSuspendJobsForDocumentWithSupportiveTranslationUnit)
{ {
Document document = documents.create({fileContainer1})[0]; Document document = documents.create({fileContainer1})[0];
document.setIsSuspended(false); document.setIsSuspended(false);
document.setIsVisibleInEditor(false, Clock::now()); document.setIsVisibleInEditor(false, Clock::now());
document.translationUnits().createAndAppend(); // Add supportive translation unit document.translationUnits().createAndAppend(); // Add supportive translation unit
setParsed(document);
const SuspendResumeJobs expectedJobs = { const SuspendResumeJobs expectedJobs = {
{document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed}, {document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed},
{document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::PreviouslyParsed}, {document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::PreviouslyParsed},
@@ -258,6 +273,7 @@ TEST_F(DocumentSuspenderResumer, CreateSuspendAndResumeJobs)
Document hotDocument = documents.create({fileContainer1})[0]; Document hotDocument = documents.create({fileContainer1})[0];
hotDocument.setIsSuspended(true); hotDocument.setIsSuspended(true);
Document coldDocument = documents.create({fileContainer2})[0]; Document coldDocument = documents.create({fileContainer2})[0];
setParsed(coldDocument);
coldDocument.setIsSuspended(false); coldDocument.setIsSuspended(false);
documents.setVisibleInEditors({filePath1}); documents.setVisibleInEditors({filePath1});
const SuspendResumeJobs expectedJobs = { const SuspendResumeJobs expectedJobs = {
@@ -292,4 +308,15 @@ DocumentSuspenderResumer::createSuspendResumeJobs(int hotDocumentsSize)
return ClangBackEnd::createSuspendResumeJobs(documents.documents(), hotDocumentsSize); return ClangBackEnd::createSuspendResumeJobs(documents.documents(), hotDocumentsSize);
} }
void DocumentSuspenderResumer::setParsed(ClangBackEnd::Document &document)
{
const Utf8String first = document.translationUnit().id();
document.translationUnits().updateParseTimePoint(first, Clock::now());
const Utf8String second
= document.translationUnit(PreferredTranslationUnit::LastUninitialized).id();
if (second != first)
document.translationUnits().updateParseTimePoint(second, Clock::now());
}
} // anonymous } // anonymous