Commit df796e2a authored by Eike Ziller's avatar Eike Ziller

Merge remote-tracking branch 'origin/4.4'

Change-Id: Id525d68a899f2db14c2d52c200a3a2a8a4e81590
parents 7b52aa2a 1b89ccb8
......@@ -195,6 +195,31 @@
save space.
\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
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.
\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
You use QDoc to build the documentation. Build the documentation from time
......
......@@ -269,4 +269,71 @@ QTCREATOR_UTILS_EXPORT bool readMultiLineString(const QJsonValue &value, QString
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
......@@ -79,4 +79,6 @@ private:
QTCREATOR_UTILS_EXPORT void expandMacros(QString *str, AbstractMacroExpander *mx);
QTCREATOR_UTILS_EXPORT QString expandMacros(const QString &str, AbstractMacroExpander *mx);
QTCREATOR_UTILS_EXPORT int parseUsedPortFromNetstatOutput(const QByteArray &line);
} // namespace Utils
......@@ -164,7 +164,7 @@ bool OpenOcdGdbServerProvider::isValid() const
}
if (m == StartupOnNetwork || m == StartupOnPipe) {
if (m_executableFile.isEmpty() || m_configurationFile.isEmpty())
if (m_executableFile.isEmpty())
return false;
}
......
......@@ -98,6 +98,8 @@ void CppUseSelectionsUpdater::update(CallType callType)
const int startRevision = cppEditorDocument->document()->revision();
QFuture<CursorInfo> future = cppEditorDocument->cursorInfo(params);
if (future.isCanceled())
return;
// QFuture::waitForFinished seems to block completely, not even
// allowing to process events from QLocalSocket.
......
......@@ -358,6 +358,9 @@ QFuture<CursorInfo> BuiltinCursorInfo::run(const CursorInfoParams &cursorInfoPar
CppTools::SemanticInfo::LocalUseMap
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();
FunctionDefinitionUnderCursor functionDefinitionUnderCursor(document->translationUnit());
DeclarationAST *declaration = functionDefinitionUnderCursor(ast,
......
......@@ -2490,6 +2490,8 @@ void DebuggerPluginPrivate::cleanupViews()
bool keepIt = true;
if (document->isModified())
keepIt = true;
else if (document->filePath().toString().contains("qeventdispatcher"))
keepIt = false;
else if (isMemory)
keepIt = !closeMemory;
else
......
......@@ -85,6 +85,11 @@ HelpViewer::HelpViewer(QWidget *parent)
{
}
HelpViewer::~HelpViewer()
{
restoreOverrideCursor();
}
void HelpViewer::setActionVisible(Action action, bool visible)
{
if (visible)
......@@ -156,16 +161,25 @@ void HelpViewer::home()
void HelpViewer::slotLoadStarted()
{
++m_loadOverrideStack;
QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
}
void HelpViewer::slotLoadFinished()
{
QGuiApplication::restoreOverrideCursor();
restoreOverrideCursor();
emit sourceChanged(source());
emit loadFinished();
}
void HelpViewer::restoreOverrideCursor()
{
while (m_loadOverrideStack > 0) {
--m_loadOverrideStack;
QGuiApplication::restoreOverrideCursor();
}
}
bool HelpViewer::handleForwardBackwardMouseButtons(QMouseEvent *event)
{
if (event->button() == Qt::XButton1) {
......
......@@ -49,7 +49,7 @@ public:
Q_DECLARE_FLAGS(Actions, Action)
explicit HelpViewer(QWidget *parent = 0);
~HelpViewer() { }
~HelpViewer();
virtual QFont viewerFont() const = 0;
virtual void setViewerFont(const QFont &font) = 0;
......@@ -109,7 +109,10 @@ protected:
void slotLoadStarted();
void slotLoadFinished();
void restoreOverrideCursor();
Actions m_visibleActions = 0;
int m_loadOverrideStack = 0;
};
} // namespace Internal
......
......@@ -110,8 +110,8 @@ private:
protected:
void mouseMoveEvent(QMouseEvent *ev)
{
int line = cursorForPosition(ev->pos()).block().blockNumber();
if (m_taskids.value(line, 0))
const int line = cursorForPosition(ev->pos()).block().blockNumber();
if (m_taskids.contains(line) && m_mousePressButton == Qt::NoButton)
viewport()->setCursor(Qt::PointingHandCursor);
else
viewport()->setCursor(Qt::IBeamCursor);
......@@ -121,23 +121,27 @@ protected:
void mousePressEvent(QMouseEvent *ev)
{
m_mousePressPosition = ev->pos();
m_mousePressButton = ev->button();
QPlainTextEdit::mousePressEvent(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();
if (unsigned taskid = m_taskids.value(line, 0))
TaskHub::showTaskInEditor(taskid);
}
m_mousePressButton = Qt::NoButton;
QPlainTextEdit::mouseReleaseEvent(ev);
}
private:
QHash<int, unsigned int> m_taskids; //Map blocknumber to taskId
QPoint m_mousePressPosition;
Qt::MouseButton m_mousePressButton = Qt::NoButton;
};
} // namespace Internal
......
......@@ -39,6 +39,7 @@
#include <utils/environment.h>
#include <utils/hostosinfo.h>
#include <utils/portlist.h>
#include <utils/stringutils.h>
#include <QCoreApplication>
......@@ -168,65 +169,10 @@ class DesktopPortsGatheringMethod : public PortsGatheringMethod
{
QList<Utils::Port> ports;
const QList<QByteArray> lines = output.split('\n');
if (HostOsInfo::isWindowsHost()) {
// 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
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());
}
}
for (const QByteArray &line : lines) {
const Port port(Utils::parseUsedPortFromNetstatOutput(line));
if (port.isValid() && !ports.contains(port))
ports.append(port);
}
return ports;
}
......
......@@ -150,6 +150,11 @@ bool Document::isIntact() const
&& !d->hasParseOrReparseFailed;
}
bool Document::isParsed() const
{
return d->translationUnits.areAllTranslationUnitsParsed();
}
Utf8String Document::filePath() const
{
checkIfNull();
......
......@@ -77,6 +77,7 @@ public:
bool isNull() const;
bool isIntact() const;
bool isParsed() const;
Utf8String filePath() const;
Utf8StringVector fileArguments() const;
......
......@@ -97,7 +97,8 @@ static bool isSuspendable(const Document &document)
{
return isFineDocument(document)
&& !document.isSuspended()
&& !document.isVisibleInEditor();
&& !document.isVisibleInEditor()
&& document.isParsed();
}
static bool isResumable(const Document &document)
......
......@@ -82,6 +82,8 @@ private slots:
void testMacroExpander();
void testStripAccelerator();
void testStripAccelerator_data();
void testParseUsedPortFromNetstatOutput();
void testParseUsedPortFromNetstatOutput_data();
private:
TestMacroExpander mx;
......@@ -202,6 +204,37 @@ void tst_StringUtils::testStripAccelerator_data()
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)
#include "tst_stringutils.moc"
......@@ -73,6 +73,7 @@ protected:
Document getDocument(const Utf8String &filePath);
void categorizeDocuments(int hotDocumentsSize);
SuspendResumeJobs createSuspendResumeJobs(int hotDocumentsSize = -1);
static void setParsed(Document &document);
protected:
ClangBackEnd::ProjectParts projects;
......@@ -176,6 +177,8 @@ TEST_F(DocumentSuspenderResumer, CreateSuspendJobForInvisible)
Document document = documents.create({fileContainer1})[0];
document.setIsSuspended(false);
document.setIsVisibleInEditor(false, Clock::now());
setParsed(document);
const SuspendResumeJobs expectedJobs = {
{document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed}
};
......@@ -196,12 +199,24 @@ TEST_F(DocumentSuspenderResumer, DoNotCreateSuspendJobForVisible)
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)
{
Document document = documents.create({fileContainer1})[0];
document.setIsSuspended(false);
document.setIsVisibleInEditor(false, Clock::now());
document.translationUnits().createAndAppend(); // Add supportive translation unit
setParsed(document);
const SuspendResumeJobs expectedJobs = {
{document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed},
{document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::PreviouslyParsed},
......@@ -258,6 +273,7 @@ TEST_F(DocumentSuspenderResumer, CreateSuspendAndResumeJobs)
Document hotDocument = documents.create({fileContainer1})[0];
hotDocument.setIsSuspended(true);
Document coldDocument = documents.create({fileContainer2})[0];
setParsed(coldDocument);
coldDocument.setIsSuspended(false);
documents.setVisibleInEditors({filePath1});
const SuspendResumeJobs expectedJobs = {
......@@ -292,4 +308,15 @@ DocumentSuspenderResumer::createSuspendResumeJobs(int 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment