diff options
author | Erik Verbruggen <erik.verbruggen@digia.com> | 2013-12-10 12:53:20 +0100 |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@digia.com> | 2013-12-10 12:53:20 +0100 |
commit | 9f831dde07cb2411808534e76669b28a1b76e21d (patch) | |
tree | ed6252d64c9a3ab27aa93786272cda1b6008f3c7 /src | |
parent | cdac81f896ef4b052d76f96485a08e6ec13696b8 (diff) | |
parent | ea1a92484ac99057b06130a012164bf9788650e9 (diff) | |
download | qt-creator-9f831dde07cb2411808534e76669b28a1b76e21d.tar.gz |
Merge remote-tracking branch 'origin/master' into wip/clangwip/clang
Change-Id: I8a2c8068a3f2b15034fb1bf6304c9a0f3f0e3c8f
Diffstat (limited to 'src')
244 files changed, 3887 insertions, 7872 deletions
diff --git a/src/libs/3rdparty/cplusplus/Keywords.cpp b/src/libs/3rdparty/cplusplus/Keywords.cpp index 91c9ffc312..9bce1ff3f8 100644 --- a/src/libs/3rdparty/cplusplus/Keywords.cpp +++ b/src/libs/3rdparty/cplusplus/Keywords.cpp @@ -803,6 +803,17 @@ static inline int classify8(const char *s, LanguageFeatures features) } } } + else if (s[3] == 'h') { + if (s[4] == 'r') { + if (s[5] == 'e') { + if (s[6] == 'a') { + if (s[7] == 'd') { + return T___THREAD; + } + } + } + } + } } } } @@ -1443,6 +1454,31 @@ static inline int classify12(const char *s, LanguageFeatures features) } } } + else if (features.cxx11Enabled && s[0] == 't') { + if (s[1] == 'h') { + if (s[2] == 'r') { + if (s[3] == 'e') { + if (s[4] == 'a') { + if (s[5] == 'd') { + if (s[6] == '_') { + if (s[7] == 'l') { + if (s[8] == 'o') { + if (s[9] == 'c') { + if (s[10] == 'a') { + if (s[11] == 'l') { + return T_THREAD_LOCAL; + } + } + } + } + } + } + } + } + } + } + } + } return T_IDENTIFIER; } diff --git a/src/libs/3rdparty/cplusplus/Lexer.cpp b/src/libs/3rdparty/cplusplus/Lexer.cpp index 6e6e6c2feb..0e0d1f4330 100644 --- a/src/libs/3rdparty/cplusplus/Lexer.cpp +++ b/src/libs/3rdparty/cplusplus/Lexer.cpp @@ -297,7 +297,24 @@ void Lexer::scan_helper(Token *tok) break; case '?': - tok->f.kind = T_QUESTION; + if (_yychar == '?') { + yyinp(); + if (_yychar == '(') { + yyinp(); + tok->f.kind = T_LBRACKET; + } else if (_yychar == ')') { + yyinp(); + tok->f.kind = T_RBRACKET; + } else if (_yychar == '<') { + yyinp(); + tok->f.kind = T_LBRACE; + } else if (_yychar == '>') { + yyinp(); + tok->f.kind = T_RBRACE; + } + } else { + tok->f.kind = T_QUESTION; + } break; case '+': diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 51e78abe5c..467bf6e694 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -3725,7 +3725,10 @@ bool Parser::lookAtStorageClassSpecifier() const case T_EXTERN: case T_MUTABLE: case T_TYPEDEF: + case T___THREAD: return true; + case T_THREAD_LOCAL: + return _languageFeatures.cxx11Enabled; case T_CONSTEXPR: if (_languageFeatures.cxx11Enabled) return true; diff --git a/src/libs/3rdparty/cplusplus/Token.cpp b/src/libs/3rdparty/cplusplus/Token.cpp index ab6d3c0317..1469edea7f 100644 --- a/src/libs/3rdparty/cplusplus/Token.cpp +++ b/src/libs/3rdparty/cplusplus/Token.cpp @@ -57,13 +57,13 @@ const char *token_names[] = { ("nullptr"), ("operator"), ("private"), ("protected"), ("public"), ("register"), ("reinterpret_cast"), ("return"), ("short"), ("signed"), ("sizeof"), ("static"),("static_assert"), - ("static_cast"), ("struct"), ("switch"), ("template"), ("this"), + ("static_cast"), ("struct"), ("switch"), ("template"), ("this"), ("thread_local"), ("throw"), ("true"), ("try"), ("typedef"), ("typeid"), ("typename"), ("union"), ("unsigned"), ("using"), ("virtual"), ("void"), ("volatile"), ("wchar_t"), ("while"), // gnu - ("__attribute__"), ("__typeof__"), + ("__attribute__"), ("__thread"), ("__typeof__"), // objc @keywords ("@catch"), ("@class"), ("@compatibility_alias"), ("@defs"), ("@dynamic"), diff --git a/src/libs/3rdparty/cplusplus/Token.h b/src/libs/3rdparty/cplusplus/Token.h index 6107c52538..58fcee3a48 100644 --- a/src/libs/3rdparty/cplusplus/Token.h +++ b/src/libs/3rdparty/cplusplus/Token.h @@ -173,6 +173,7 @@ enum Kind { T_SWITCH, T_TEMPLATE, T_THIS, + T_THREAD_LOCAL, T_THROW, T_TRUE, T_TRY, @@ -189,6 +190,7 @@ enum Kind { T_WHILE, T___ATTRIBUTE__, + T___THREAD, T___TYPEOF__, // obj c++ @ keywords diff --git a/src/libs/cplusplus/MatchingText.h b/src/libs/cplusplus/MatchingText.h index 5b12d5cc78..32db6df60a 100644 --- a/src/libs/cplusplus/MatchingText.h +++ b/src/libs/cplusplus/MatchingText.h @@ -36,9 +36,6 @@ QT_FORWARD_DECLARE_CLASS(QChar) namespace CPlusPlus { -class BackwardsScanner; -class TokenCache; - class CPLUSPLUS_EXPORT MatchingText { public: diff --git a/src/libs/cplusplus/TypePrettyPrinter.cpp b/src/libs/cplusplus/TypePrettyPrinter.cpp index 6ec363ba92..364edb66af 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.cpp +++ b/src/libs/cplusplus/TypePrettyPrinter.cpp @@ -436,7 +436,7 @@ void TypePrettyPrinter::visit(Function *type) if (_overview->showDefaultArguments) { if (const StringLiteral *initializer = arg->initializer()) { - _text += QLatin1String(" ="); + _text += QLatin1String(" = "); _text += QString::fromUtf8(initializer->chars(), initializer->size()); } } diff --git a/src/libs/qmljs/persistenttrie.cpp b/src/libs/qmljs/persistenttrie.cpp index 74c9593c7d..521d90f31c 100644 --- a/src/libs/qmljs/persistenttrie.cpp +++ b/src/libs/qmljs/persistenttrie.cpp @@ -654,7 +654,7 @@ int matchStrength(const QString &searchStr, const QString &str) { QString::const_iterator i = searchStr.constBegin(), iEnd = searchStr.constEnd(), j = str.constBegin(), jEnd = str.constEnd(); - bool lastWasNotUpper=true, lastWasSpacer=true, lastWasMatch = false; + bool lastWasNotUpper=true, lastWasSpacer=true, lastWasMatch = false, didJump = false; int res = 0; while (i != iEnd && j != jEnd) { bool thisIsUpper = (*j).isUpper(); @@ -667,6 +667,7 @@ int matchStrength(const QString &searchStr, const QString &str) lastWasMatch = true; ++i; } else { + didJump = true; lastWasMatch = false; } ++j; @@ -674,9 +675,11 @@ int matchStrength(const QString &searchStr, const QString &str) lastWasSpacer = !thisIsLetterOrNumber; } if (i != iEnd) - return iEnd - i; + return i - iEnd; if (j == jEnd) ++res; + if (!didJump) + res+=2; return res; } diff --git a/src/libs/qmljs/qmljsimportdependencies.cpp b/src/libs/qmljs/qmljsimportdependencies.cpp index dffcf8ee4b..9dc0e53f54 100644 --- a/src/libs/qmljs/qmljsimportdependencies.cpp +++ b/src/libs/qmljs/qmljsimportdependencies.cpp @@ -314,7 +314,7 @@ int ImportKey::compare(const ImportKey &other) const QString v2 = other.splitPath.at(i); if (v1 < v2) return -1; - if (v2 > v1) + if (v1 > v2) return 1; } if (len1 < len2) @@ -626,7 +626,7 @@ void ImportDependencies::iterateOnCandidateImports( break; default: { - QStringList imp = m_importCache.value(key.flatKey()); + const QStringList imp = m_importCache.value(key.flatKey()); foreach (const QString &cImportName, imp) { CoreImport cImport = coreImport(cImportName); if (vContext.languageIsCompatible(cImport.language)) { @@ -928,4 +928,38 @@ QSet<ImportKey> ImportDependencies::subdirImports( return res; } +void ImportDependencies::checkConsistency() const +{ + QMapIterator<ImportKey, QStringList> j(m_importCache); + while (j.hasNext()) { + j.next(); + foreach (const QString &s, j.value()) { + bool found = false; + foreach (const Export &e, m_coreImports.value(s).possibleExports) + if (e.exportName == j.key()) + found = true; + Q_ASSERT(found); + } + } + QMapIterator<QString,CoreImport> i(m_coreImports); + while (i.hasNext()) { + i.next(); + foreach (const Export &e, i.value().possibleExports) { + if (!m_importCache.value(e.exportName).contains(i.key())) { + qDebug() << e.exportName.toString(); + qDebug() << i.key(); + + QMapIterator<ImportKey, QStringList> j(m_importCache); + while (j.hasNext()) { + j.next(); + qDebug() << j.key().toString() << j.value(); + } + qDebug() << m_importCache.contains(e.exportName); + qDebug() << m_importCache.value(e.exportName); + } + Q_ASSERT(m_importCache.value(e.exportName).contains(i.key())); + } + } +} + } // namespace QmlJS diff --git a/src/libs/qmljs/qmljsimportdependencies.h b/src/libs/qmljs/qmljsimportdependencies.h index fc84f0794f..1e27ef0626 100644 --- a/src/libs/qmljs/qmljsimportdependencies.h +++ b/src/libs/qmljs/qmljsimportdependencies.h @@ -223,6 +223,7 @@ public: QSet<ImportKey> libraryImports(const ViewerContext &viewContext) const; QSet<ImportKey> subdirImports(const ImportKey &baseKey, const ViewerContext &viewContext) const; + void checkConsistency() const; private: void removeImportCacheEntry(const ImportKey &importKey, const QString &importId); diff --git a/src/libs/qmljs/qmljsreformatter.cpp b/src/libs/qmljs/qmljsreformatter.cpp index 9295fcc319..d940cd1c65 100644 --- a/src/libs/qmljs/qmljsreformatter.cpp +++ b/src/libs/qmljs/qmljsreformatter.cpp @@ -139,11 +139,6 @@ protected: Node::accept(node, this); } - void acceptIndented(Node *node) - { - accept(node); - } - void lnAcceptIndented(Node *node) { newLine(); diff --git a/src/libs/qmljs/qmljsstaticanalysismessage.cpp b/src/libs/qmljs/qmljsstaticanalysismessage.cpp index 6f6de15fdc..235639ce32 100644 --- a/src/libs/qmljs/qmljsstaticanalysismessage.cpp +++ b/src/libs/qmljs/qmljsstaticanalysismessage.cpp @@ -210,14 +210,14 @@ StaticAnalysisMessages::StaticAnalysisMessages() tr("%1 elements expected in array value."), 1); newMsg(WarnImperativeCodeNotEditableInVisualDesigner, Error, tr("Imperative code is not supported in the Qt Quick Designer.")); - newMsg(WarnUnsupportedTypeInVisualDesigner, Error, + newMsg(WarnUnsupportedTypeInVisualDesigner, Warning, tr("This type is not supported in the Qt Quick Designer.")); newMsg(WarnReferenceToParentItemNotSupportedByVisualDesigner, Error, tr("Reference to parent item cannot be resolved correctly by the Qt Quick Designer.")); - newMsg(WarnUndefinedValueForVisualDesigner, Error, + newMsg(WarnUndefinedValueForVisualDesigner, Warning, tr("This visual property binding cannot be evaluated in the local context " "and might not show up in Qt Quick Designer as expected.")); - newMsg(WarnStatesOnlyInRootItemForVisualDesigner, Error, + newMsg(WarnStatesOnlyInRootItemForVisualDesigner, Warning, tr("Qt Quick Designer only supports states in the root item.")); newMsg(WarnAboutQtQuick1InsteadQtQuick2, Warning, tr("Using Qt Quick 1 code model instead of Qt Quick 2.")); diff --git a/src/libs/qtcreatorcdbext/containers.cpp b/src/libs/qtcreatorcdbext/containers.cpp index 8fbd64f0a5..3b6f9362dd 100644 --- a/src/libs/qtcreatorcdbext/containers.cpp +++ b/src/libs/qtcreatorcdbext/containers.cpp @@ -203,7 +203,18 @@ int containerSize(KnownType kt, const SymbolGroupValue &v) if (const SymbolGroupValue deque = v[unsigned(0)]) return containerSize(KT_StdDeque, deque); break; + case KT_StdArray: { + std::string::size_type arraySizeStart = v.type().find(','); + if (arraySizeStart != std::string::npos) { + ++arraySizeStart; + std::string::size_type arraySizeEnd = v.type().find('>', arraySizeStart); + if (arraySizeEnd != std::string::npos) + return std::stoi(v.type().substr(arraySizeStart, arraySizeEnd - arraySizeStart)); + } + break; } + } + return -1; } @@ -253,6 +264,22 @@ static inline AbstractSymbolGroupNodePtrVector stdListChildList(SymbolGroupNode return AbstractSymbolGroupNodePtrVector(); } +static inline AbstractSymbolGroupNodePtrVector stdArrayChildList(SymbolGroupNode *n, int count, + const SymbolGroupValueContext &ctx) +{ + AbstractSymbolGroupNodePtrVector rc; + if (SymbolGroupValue elems = SymbolGroupValue(n, ctx)["_Elems"]) { + rc.reserve(count); + for (int i = 0; i < count; ++i) { + if (const SymbolGroupValue value = elems[i]) + rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, value.node())); + else + break; + } + } + return rc; +} + // QLinkedList<T>: Dummy head node and then a linked list of "n", "t". static inline AbstractSymbolGroupNodePtrVector qLinkedListChildList(SymbolGroupNode *n, int count, const SymbolGroupValueContext &ctx) @@ -1109,6 +1136,8 @@ AbstractSymbolGroupNodePtrVector containerChildren(SymbolGroupNode *node, int ty break; case KT_StdList: return stdListChildList(node, size , ctx); + case KT_StdArray: + return stdArrayChildList(node, size , ctx); case KT_StdDeque: return stdDequeChildList(SymbolGroupValue(node, ctx), size); case KT_StdStack: diff --git a/src/libs/qtcreatorcdbext/knowntype.h b/src/libs/qtcreatorcdbext/knowntype.h index ee609567bc..206f971ebf 100644 --- a/src/libs/qtcreatorcdbext/knowntype.h +++ b/src/libs/qtcreatorcdbext/knowntype.h @@ -72,6 +72,7 @@ enum KnownType KT_QBasicAtomicInt = KT_Qt_Type + KT_HasSimpleDumper + 18, KT_QAtomicInt = KT_Qt_Type + KT_HasSimpleDumper + 19, KT_QStringRef = KT_Qt_Type + KT_HasSimpleDumper + 20, + KT_QTextCursor = KT_Qt_Type + KT_HasSimpleDumper + 21, KT_QObject = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 20, KT_QWindow = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 21, KT_QWidget = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 22, @@ -173,7 +174,8 @@ enum KnownType KT_StdDeque = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 4, KT_StdSet = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 5, KT_StdMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 6, - KT_StdMultiMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 7 + KT_StdMultiMap = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 7, + KT_StdArray = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 8 }; #endif // KNOWNTYPE_H diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp index 19635c4212..f7d13fa08c 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp @@ -1078,6 +1078,8 @@ static KnownType knownClassTypeHelper(const std::string &type, return KT_StdStack; if (!type.compare(hPos, 5, "deque")) return KT_StdDeque; + if (!type.compare(hPos, 5, "array")) + return KT_StdArray; break; case 6: if (!type.compare(hPos, 6, "vector")) @@ -1281,6 +1283,8 @@ static KnownType knownClassTypeHelper(const std::string &type, return KT_QFixedPoint; if (!type.compare(qPos, 11, "QScriptLine")) return KT_QScriptLine; + if (!type.compare(qPos, 11, "QTextCursor")) + return KT_QTextCursor; break; case 12: if (!type.compare(qPos, 12, "QKeySequence")) @@ -2383,6 +2387,18 @@ static inline bool dumpQWindow(const SymbolGroupValue &v, std::wostream &str, vo return true; } +//Dump a QTextCursor +static inline bool dumpQTextCursor(const SymbolGroupValue &v, std::wostream &str) +{ + const unsigned offset = SymbolGroupValue::pointerSize() + SymbolGroupValue::sizeOf("double"); + const ULONG64 posAddr = addressOfQPrivateMember(v, QPDM_qSharedDataPadded, offset); + if (!posAddr) + return false; + const int position = SymbolGroupValue::readIntValue(v.context().dataspaces, posAddr); + str << position; + return true; +} + // Dump a std::string. static bool dumpStd_W_String(const SymbolGroupValue &v, int type, std::wostream &str, MemoryHandle **memoryHandle = 0) @@ -2796,6 +2812,10 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, case KT_StdWString: rc = dumpStd_W_String(v, kt, str, memoryHandleIn) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed; break; + case KT_QTextCursor: + rc = dumpQTextCursor(v, str) ? SymbolGroupNode::SimpleDumperOk + : SymbolGroupNode::SimpleDumperFailed; + break; default: break; } diff --git a/src/libs/utils/detailsbutton.cpp b/src/libs/utils/detailsbutton.cpp index 66bf24172e..43fbd74d6e 100644 --- a/src/libs/utils/detailsbutton.cpp +++ b/src/libs/utils/detailsbutton.cpp @@ -37,6 +37,10 @@ #include <QPainter> #include <QStyleOption> +#if QT_VERSION >= 0x050100 +#include <QGuiApplication> +#endif + using namespace Utils; FadingWidget::FadingWidget(QWidget *parent) : @@ -123,12 +127,19 @@ void DetailsButton::paintEvent(QPaintEvent *e) if (!HostOsInfo::isMacHost() && !isDown() && m_fader > 0) p.fillRect(rect().adjusted(1, 1, -2, -2), QColor(255, 255, 255, int(m_fader*180))); + qreal checkedPixmapRatio = 1.0; + qreal uncheckedPixmapRatio = 1.0; +#if QT_VERSION >= 0x050100 + checkedPixmapRatio = m_checkedPixmap.devicePixelRatio(); + uncheckedPixmapRatio = m_uncheckedPixmap.devicePixelRatio(); +#endif + if (isChecked()) { - if (m_checkedPixmap.isNull() || m_checkedPixmap.size() != contentsRect().size()) + if (m_checkedPixmap.isNull() || m_checkedPixmap.size() / checkedPixmapRatio != contentsRect().size()) m_checkedPixmap = cacheRendering(contentsRect().size(), true); p.drawPixmap(contentsRect(), m_checkedPixmap); } else { - if (m_uncheckedPixmap.isNull() || m_uncheckedPixmap.size() != contentsRect().size()) + if (m_uncheckedPixmap.isNull() || m_uncheckedPixmap.size() / uncheckedPixmapRatio != contentsRect().size()) m_uncheckedPixmap = cacheRendering(contentsRect().size(), false); p.drawPixmap(contentsRect(), m_uncheckedPixmap); } @@ -145,7 +156,14 @@ QPixmap DetailsButton::cacheRendering(const QSize &size, bool checked) lg.setCoordinateMode(QGradient::ObjectBoundingMode); lg.setFinalStop(0, 1); - QPixmap pixmap(size); + qreal pixelRatio = 1.0; +#if QT_VERSION >= 0x050100 + pixelRatio = devicePixelRatio(); +#endif + QPixmap pixmap(size * pixelRatio); +#if QT_VERSION >= 0x050100 + pixmap.setDevicePixelRatio(pixelRatio); +#endif pixmap.fill(Qt::transparent); QPainter p(&pixmap); p.setRenderHint(QPainter::Antialiasing, true); diff --git a/src/plugins/qmlprofiler/canvas/qdeclarativecanvastimer.cpp b/src/libs/utils/execmenu.cpp index 8069fbbcb7..b760132801 100644 --- a/src/plugins/qmlprofiler/canvas/qdeclarativecanvastimer.cpp +++ b/src/libs/utils/execmenu.cpp @@ -27,59 +27,45 @@ ** ****************************************************************************/ -#include "qdeclarativecanvastimer_p.h" +#include "execmenu.h" -#include <QJSEngine> -#include <QJSValue> -#include <qtimer.h> +#include <QApplication> +#include <QDesktopWidget> +#include <QMenu> +#include <QPoint> +#include <QRect> +#include <QSize> +#include <QWidget> -QT_BEGIN_NAMESPACE +namespace Utils { -Q_GLOBAL_STATIC(QList<CanvasTimer*> , activeTimers); - -CanvasTimer::CanvasTimer(QObject *parent, const QJSValue &data) - : QTimer(parent), m_value(data) +/*! + * Opens \a menu at the specified \a widget position. + * This function computes the position where to show the menu, and opens it with + * QMenu::exec(). + */ +QAction *execMenuAtWidget(QMenu *menu, QWidget *widget) { -} - -void CanvasTimer::handleTimeout() -{ - Q_ASSERT(m_value.isCallable()); - m_value.call(); - if (isSingleShot()) - removeTimer(this); -} - -void CanvasTimer::createTimer(QObject *parent, const QJSValue &val, long timeout, bool singleshot) -{ - - CanvasTimer *timer = new CanvasTimer(parent, val); - timer->setInterval(timeout); - timer->setSingleShot(singleshot); - connect(timer, SIGNAL(timeout()), timer, SLOT(handleTimeout())); - activeTimers()->append(timer); - timer->start(); -} - -void CanvasTimer::removeTimer(CanvasTimer *timer) -{ - activeTimers()->removeAll(timer); - timer->deleteLater(); -} - -void CanvasTimer::removeTimer(const QJSValue &val) -{ - if (!val.isCallable()) - return; - - for (int i = 0 ; i < activeTimers()->count() ; ++i) { - CanvasTimer *timer = activeTimers()->at(i); - if (timer->equals(val)) { - removeTimer(timer); - return; - } + QPoint p; + QRect screen = qApp->desktop()->availableGeometry(widget); + QSize sh = menu->sizeHint(); + QRect rect = widget->rect(); + if (widget->isRightToLeft()) { + if (widget->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.height()) + p = widget->mapToGlobal(rect.bottomRight()); + else + p = widget->mapToGlobal(rect.topRight() - QPoint(0, sh.height())); + p.rx() -= sh.width(); + } else { + if (widget->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.height()) + p = widget->mapToGlobal(rect.bottomLeft()); + else + p = widget->mapToGlobal(rect.topLeft() - QPoint(0, sh.height())); } -} + p.rx() = qMax(screen.left(), qMin(p.x(), screen.right() - sh.width())); + p.ry() += 1; -QT_END_NAMESPACE + return menu->exec(p); +} +} // namespace Utils diff --git a/src/plugins/qmlprofiler/canvas/qdeclarativecanvastimer_p.h b/src/libs/utils/execmenu.h index b25a98eb44..0a385c2d07 100644 --- a/src/plugins/qmlprofiler/canvas/qdeclarativecanvastimer_p.h +++ b/src/libs/utils/execmenu.h @@ -27,36 +27,21 @@ ** ****************************************************************************/ -#ifndef QDECLARATIVECANVASTIMER_P_H -#define QDECLARATIVECANVASTIMER_P_H +#ifndef EXECMENU_H +#define EXECMENU_H -#include <QJSValue> -#include <qtimer.h> -#include <qlist.h> +#include "utils_global.h" QT_BEGIN_NAMESPACE +class QAction; +class QMenu; +class QWidget; +QT_END_NAMESPACE -class CanvasTimer : public QTimer -{ - Q_OBJECT - -public: - CanvasTimer(QObject *parent, const QJSValue &data); - -public Q_SLOTS: - void handleTimeout(); - bool equals(const QJSValue &value){return m_value.equals(value);} - -public: - static void createTimer(QObject *parent, const QJSValue &val, long timeout, bool singleshot); - static void removeTimer(CanvasTimer *timer); - static void removeTimer(const QJSValue &); - -private: - QJSValue m_value; +namespace Utils { -}; +QTCREATOR_UTILS_EXPORT QAction *execMenuAtWidget(QMenu *menu, QWidget *widget); -QT_END_NAMESPACE +} // namespace Utils -#endif // QDECLARATIVECANVASTIMER_P_H +#endif // EXECMENU_H diff --git a/src/libs/utils/fancylineedit.cpp b/src/libs/utils/fancylineedit.cpp index d945852698..ed80be0ba0 100644 --- a/src/libs/utils/fancylineedit.cpp +++ b/src/libs/utils/fancylineedit.cpp @@ -27,14 +27,13 @@ ** ****************************************************************************/ +#include "execmenu.h" #include "fancylineedit.h" #include "historycompleter.h" #include "qtcassert.h" #include <QAbstractItemView> -#include <QApplication> #include <QDebug> -#include <QDesktopWidget> #include <QKeyEvent> #include <QMenu> #include <QPainter> @@ -42,35 +41,6 @@ #include <QStyle> /*! - * Opens \a menu at the specified \a widget position. - * This function computes the position where to show the menu, and opens it with - * QMenu::exec(). - */ -static void execMenuAtWidget(QMenu *menu, QWidget *widget) -{ - QPoint p; - QRect screen = qApp->desktop()->availableGeometry(widget); - QSize sh = menu->sizeHint(); - QRect rect = widget->rect(); - if (widget->isRightToLeft()) { - if (widget->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.height()) - p = widget->mapToGlobal(rect.bottomRight()); - else - p = widget->mapToGlobal(rect.topRight() - QPoint(0, sh.height())); - p.rx() -= sh.width(); - } else { - if (widget->mapToGlobal(QPoint(0, rect.bottom())).y() + sh.height() <= screen.height()) - p = widget->mapToGlobal(rect.bottomLeft()); - else - p = widget->mapToGlobal(rect.topLeft() - QPoint(0, sh.height())); - } - p.rx() = qMax(screen.left(), qMin(p.x(), screen.right() - sh.width())); - p.ry() += 1; - - menu->exec(p); -} - -/*! \class Utils::FancyLineEdit \brief The FancyLineEdit class is a line edit with an embedded pixmap on diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 97833eb8e7..2825a5661f 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -86,7 +86,8 @@ SOURCES += $$PWD/environment.cpp \ $$PWD/tooltip/tipcontents.cpp \ $$PWD/unixutils.cpp \ $$PWD/function.cpp \ - $$PWD/ansiescapecodehandler.cpp + $$PWD/ansiescapecodehandler.cpp \ + $$PWD/execmenu.cpp win32 { SOURCES += \ @@ -180,7 +181,8 @@ HEADERS += \ $$PWD/unixutils.h \ $$PWD/qtcoverride.h \ $$PWD/function.h \ - $$PWD/ansiescapecodehandler.h + $$PWD/ansiescapecodehandler.h \ + $$PWD/execmenu.h FORMS += $$PWD/filewizardpage.ui \ $$PWD/projectintropage.ui \ diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index c40db11a3e..99174d119c 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -64,6 +64,8 @@ QtcLibrary { "environment.h", "environmentmodel.cpp", "environmentmodel.h", + "execmenu.cpp", + "execmenu.h", "faketooltip.cpp", "faketooltip.h", "fancylineedit.cpp", diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index f85fd96b63..f2b2fecac0 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -164,9 +164,8 @@ AndroidConfig::AndroidConfig(const QSettings &settings) toolchainHost = settings.value(ToolchainHostKey).toString(); automaticKitCreation = settings.value(AutomaticKitCreationKey, true).toBool(); QString extraDirectory = settings.value(MakeExtraSearchDirectory).toString(); - if (extraDirectory.isEmpty()) - makeExtraSearchDirectories = QStringList(); - else + makeExtraSearchDirectories.clear(); + if (!extraDirectory.isEmpty()) makeExtraSearchDirectories << extraDirectory; PersistentSettingsReader reader; @@ -183,9 +182,8 @@ AndroidConfig::AndroidConfig(const QSettings &settings) if (v.isValid()) automaticKitCreation = v.toBool(); QString extraDirectory = reader.restoreValue(MakeExtraSearchDirectory).toString(); - if (extraDirectory.isEmpty()) - makeExtraSearchDirectories = QStringList(); - else + makeExtraSearchDirectories.clear(); + if (!extraDirectory.isEmpty()) makeExtraSearchDirectories << extraDirectory; // persistent settings } diff --git a/src/plugins/android/androiddeployqtwidget.ui b/src/plugins/android/androiddeployqtwidget.ui index a726f9134f..180bccc3b7 100644 --- a/src/plugins/android/androiddeployqtwidget.ui +++ b/src/plugins/android/androiddeployqtwidget.ui @@ -200,7 +200,7 @@ <item row="1" column="0"> <widget class="QLabel" name="targetSDKLabel"> <property name="text"> - <string>Android target SDK:</string> + <string>Android build SDK:</string> </property> </widget> </item> @@ -241,7 +241,7 @@ <item> <widget class="QLabel" name="oldFilesWarningLabel"> <property name="text"> - <string>Qt no longer uses the folder "android" in the project's source directory.</string> + <string>Qt no longer uses the folder "android" in the project's source directory.</string> </property> <property name="wordWrap"> <bool>true</bool> diff --git a/src/plugins/android/androiddeploystep.cpp b/src/plugins/android/androiddeploystep.cpp index 42ddbf125d..29b77b06ed 100644 --- a/src/plugins/android/androiddeploystep.cpp +++ b/src/plugins/android/androiddeploystep.cpp @@ -281,8 +281,7 @@ unsigned int AndroidDeployStep::remoteModificationTime(const QString &fullDestin QStringList arguments = AndroidDeviceInfo::adbSelector(m_deviceSerialNumber); arguments << QLatin1String("ls") << destination; process.start(AndroidConfigurations::instance().adbToolPath().toString(), arguments); - process.waitForFinished(5000); - if (process.error() != QProcess::UnknownError + if (!process.waitForFinished(5000) || process.exitCode() != 0) return -1; QByteArray output = process.readAll(); diff --git a/src/plugins/android/androidmanifesteditorwidget.cpp b/src/plugins/android/androidmanifesteditorwidget.cpp index 3d6b6d1057..8053f28a77 100644 --- a/src/plugins/android/androidmanifesteditorwidget.cpp +++ b/src/plugins/android/androidmanifesteditorwidget.cpp @@ -99,7 +99,8 @@ AndroidManifestEditorWidget::AndroidManifestEditorWidget(QWidget *parent, TextEd : TextEditor::PlainTextEditorWidget(parent), m_dirty(false), m_stayClean(false), - m_setAppName(false) + m_setAppName(false), + m_appNameInStringsXml(false) { QSharedPointer<AndroidManifestDocument> doc(new AndroidManifestDocument(this)); doc->setMimeType(QLatin1String(Constants::ANDROID_MANIFEST_MIME_TYPE)); @@ -586,7 +587,7 @@ void AndroidManifestEditorWidget::preSave() if (activePage() != Source) syncToEditor(); - if (m_setAppName) { + if (m_setAppName && m_appNameInStringsXml) { QString baseDir = QFileInfo(static_cast<AndroidManifestDocument *>(editor()->document())->filePath()).absolutePath(); QString fileName = baseDir + QLatin1String("/res/values/strings.xml"); QFile f(fileName); @@ -773,6 +774,8 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc) QString baseDir = QFileInfo(static_cast<AndroidManifestDocument *>(editor()->document())->filePath()).absolutePath(); QString fileName = baseDir + QLatin1String("/res/values/strings.xml"); + QDomElement applicationElement = manifest.firstChildElement(QLatin1String("application")); + QFile f(fileName); if (f.exists() && f.open(QIODevice::ReadOnly)) { QDomDocument doc; @@ -786,9 +789,13 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc) metadataElem = metadataElem.nextSiblingElement(QLatin1String("string")); } } + m_appNameInStringsXml = true; + } else { + m_appNameLineEdit->setText(applicationElement.attribute(QLatin1String("android:label"))); + m_appNameInStringsXml = false; } - QDomElement metadataElem = manifest.firstChildElement(QLatin1String("application")).firstChildElement(QLatin1String("activity")).firstChildElement(QLatin1String("meta-data")); + QDomElement metadataElem = applicationElement.firstChildElement(QLatin1String("activity")).firstChildElement(QLatin1String("meta-data")); while (!metadataElem.isNull()) { if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")) { m_targetLineEdit->setEditText(metadataElem.attribute(QLatin1String("android:value"))); @@ -893,6 +900,11 @@ void AndroidManifestEditorWidget::syncToEditor() manifest.setAttribute(QLatin1String("android:versionCode"), m_versionCode->value()); manifest.setAttribute(QLatin1String("android:versionName"), m_versionNameLinedit->text()); + if (!m_appNameInStringsXml) { + QDomElement application = manifest.firstChildElement(QLatin1String("application")); + application.setAttribute(QLatin1String("android:label"), m_appNameLineEdit->text()); + } + setUsesSdk(doc, manifest, extractVersion(m_androidMinSdkVersion->currentText()), extractVersion(m_androidTargetSdkVersion->currentText())); diff --git a/src/plugins/android/androidmanifesteditorwidget.h b/src/plugins/android/androidmanifesteditorwidget.h index 6227258ce4..cdd77ef926 100644 --- a/src/plugins/android/androidmanifesteditorwidget.h +++ b/src/plugins/android/androidmanifesteditorwidget.h @@ -138,6 +138,7 @@ private: bool m_dirty; // indicates that we need to call syncToEditor() bool m_stayClean; bool m_setAppName; + bool m_appNameInStringsXml; int m_errorLine; int m_errorColumn; diff --git a/src/plugins/android/androidsettingswidget.ui b/src/plugins/android/androidsettingswidget.ui index 7146434ad2..985ccde98c 100644 --- a/src/plugins/android/androidsettingswidget.ui +++ b/src/plugins/android/androidsettingswidget.ui @@ -323,7 +323,7 @@ <item> <widget class="QPushButton" name="manageAVDPushButton"> <property name="text"> - <string>Start Android AVD Manager</string> + <string>Start AVD Manager</string> </property> </widget> </item> diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp index a1c9c15984..505daf7f73 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp @@ -433,7 +433,7 @@ void AutotoolsProject::updateCppCodeModel() part->files << CppTools::ProjectFile(file, CppTools::ProjectFile::CXXSource); part->includePaths += m_makefileParserThread->includePaths(); - part->defines += m_makefileParserThread->defines(); + part->projectDefines += m_makefileParserThread->defines(); pinfo.appendProjectPart(part); modelManager->updateProjectInfo(pinfo); diff --git a/src/plugins/autotoolsprojectmanager/makestep.cpp b/src/plugins/autotoolsprojectmanager/makestep.cpp index 51206624c4..7eef782c69 100644 --- a/src/plugins/autotoolsprojectmanager/makestep.cpp +++ b/src/plugins/autotoolsprojectmanager/makestep.cpp @@ -312,6 +312,8 @@ QString MakeStepConfigWidget::summaryText() const void MakeStepConfigWidget::updateDetails() { BuildConfiguration *bc = m_makeStep->buildConfiguration(); + if (!bc) + bc = m_makeStep->target()->activeBuildConfiguration(); ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(m_makeStep->target()->kit()); if (tc) { diff --git a/src/plugins/bineditor/bineditor.cpp b/src/plugins/bineditor/bineditor.cpp index 2c0d7c0a36..62352b1230 100644 --- a/src/plugins/bineditor/bineditor.cpp +++ b/src/plugins/bineditor/bineditor.cpp @@ -126,11 +126,11 @@ void BinEditorWidget::init() 2*m_addressBytes + (m_addressBytes - 1) / 2; m_addressString = QString(addressStringWidth, QLatin1Char(':')); QFontMetrics fm(fontMetrics()); - m_margin = 4; m_descent = fm.descent(); m_ascent = fm.ascent(); m_lineHeight = fm.lineSpacing(); m_charWidth = fm.width(QChar(QLatin1Char('M'))); + m_margin = m_charWidth; m_columnWidth = 2 * m_charWidth + fm.width(QChar(QLatin1Char(' '))); m_numLines = m_size / m_bytesPerLine + 1; m_numVisibleLines = viewport()->height() / m_lineHeight; @@ -638,7 +638,7 @@ int BinEditorWidget::find(const QByteArray &pattern_arg, int from, if (pos >= 0) { setCursorPosition(pos); - setCursorPosition(pos + (found == pos ? pattern.size() : hexPattern.size()), KeepAnchor); + setCursorPosition(pos + (found == pos ? pattern.size() : hexPattern.size()) - 1, KeepAnchor); } return pos; } @@ -713,7 +713,7 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) QPainter painter(viewport()); const int topLine = verticalScrollBar()->value(); const int xoffset = horizontalScrollBar()->value(); - const int x1 = -xoffset + m_margin + m_labelWidth - m_charWidth/2; + const int x1 = -xoffset + m_margin + m_labelWidth - m_charWidth/2 - 1; const int x2 = -xoffset + m_margin + m_labelWidth + m_bytesPerLine * m_columnWidth + m_charWidth/2; painter.drawLine(x1, 0, x1, viewport()->height()); painter.drawLine(x2, 0, x2, viewport()->height()); @@ -836,7 +836,7 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) color = QColor(0xffef0b); if (color.isValid()) { - painter.fillRect(item_x, y-m_ascent, m_columnWidth, m_lineHeight, color); + painter.fillRect(item_x - m_charWidth/2, y-m_ascent, m_columnWidth, m_lineHeight, color); int printable_item_x = -xoffset + m_margin + m_labelWidth + m_bytesPerLine * m_columnWidth + m_charWidth + fm.width(printable.left(c)); painter.fillRect(printable_item_x, y-m_ascent, @@ -844,8 +844,8 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) m_lineHeight, color); } - if (selStart < selEnd && !isFullySelected && pos >= selStart && pos < selEnd) { - selectionRect |= QRect(item_x, y-m_ascent, m_columnWidth, m_lineHeight); + if (!isFullySelected && pos >= selStart && pos <= selEnd) { + selectionRect |= QRect(item_x - m_charWidth/2, y-m_ascent, m_columnWidth, m_lineHeight); int printable_item_x = -xoffset + m_margin + m_labelWidth + m_bytesPerLine * m_columnWidth + m_charWidth + fm.width(printable.left(c)); printableSelectionRect |= QRect(printable_item_x, y-m_ascent, @@ -856,11 +856,10 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) } int x = -xoffset + m_margin + m_labelWidth; - bool cursorWanted = m_cursorPosition == m_anchorPosition; if (isFullySelected) { painter.save(); - painter.fillRect(x, y-m_ascent, m_bytesPerLine*m_columnWidth, m_lineHeight, palette().highlight()); + painter.fillRect(x - m_charWidth/2, y-m_ascent, m_bytesPerLine*m_columnWidth, m_lineHeight, palette().highlight()); painter.setPen(palette().highlightedText().color()); drawItems(&painter, x, y, itemString); painter.restore(); @@ -878,8 +877,7 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) } } - - if (cursor >= 0 && cursorWanted) { + if (cursor >= 0) { int w = fm.boundingRect(itemString.mid(cursor*3, 2)).width(); QRect cursorRect(x + cursor * m_columnWidth, y - m_ascent, w + 1, m_lineHeight); painter.save(); @@ -919,7 +917,7 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) } } - if (cursor >= 0 && !printable.isEmpty() && cursorWanted) { + if (cursor >= 0 && !printable.isEmpty()) { QRect cursorRect(text_x + fm.width(printable.left(cursor)), y-m_ascent, fm.width(printable.at(cursor)), @@ -950,18 +948,14 @@ void BinEditorWidget::setCursorPosition(int pos, MoveMode moveMode) pos = qMin(m_size-1, qMax(0, pos)); int oldCursorPosition = m_cursorPosition; - bool hadSelection = hasSelection(); m_lowNibble = false; - if (!hadSelection) - updateLines(); m_cursorPosition = pos; if (moveMode == MoveAnchor) { - if (hadSelection) - updateLines(m_anchorPosition, oldCursorPosition); + updateLines(m_anchorPosition, oldCursorPosition); m_anchorPosition = m_cursorPosition; } - updateLines(hadSelection || hasSelection() ? oldCursorPosition : m_cursorPosition, m_cursorPosition); + updateLines(oldCursorPosition, m_cursorPosition); ensureCursorVisible(); emit cursorPositionChanged(m_cursorPosition); } @@ -1087,20 +1081,14 @@ bool BinEditorWidget::event(QEvent *e) QString BinEditorWidget::toolTip(const QHelpEvent *helpEvent) const { - // Selection if mouse is in, else 1 byte at cursor int selStart = selectionStart(); int selEnd = selectionEnd(); - int byteCount = selEnd - selStart; - if (byteCount < 1) { - selStart = posAt(helpEvent->pos()); - selEnd = selStart + 1; - byteCount = 1; - } + int byteCount = selEnd - selStart + 1; if (m_hexCursor == 0 || byteCount > 8) return QString(); const QPoint &startPoint = offsetToPos(selStart); - const QPoint &endPoint = offsetToPos(selEnd); + const QPoint &endPoint = offsetToPos(selEnd + 1); QRect selRect(startPoint, endPoint); selRect.setHeight(m_lineHeight); if (!selRect.contains(helpEvent->pos())) @@ -1385,10 +1373,7 @@ void BinEditorWidget::copy(bool raw) { int selStart = selectionStart(); int selEnd = selectionEnd(); - if (selStart > selEnd) - qSwap(selStart, selEnd); - - const int selectionLength = selEnd - selStart; + const int selectionLength = selEnd - selStart + 1; if (selectionLength >> 22) { QMessageBox::warning(this, tr("Copying Failed"), tr("You cannot copy more than 4 MB of binary data.")); @@ -1496,7 +1481,7 @@ void BinEditorWidget::redo() void BinEditorWidget::contextMenuEvent(QContextMenuEvent *event) { const int selStart = selectionStart(); - const int byteCount = selectionEnd() - selStart; + const int byteCount = selectionEnd() - selStart + 1; QPointer<QMenu> contextMenu(new QMenu(this)); diff --git a/src/plugins/bineditor/bineditor.h b/src/plugins/bineditor/bineditor.h index d02402da61..7a3f9e5efa 100644 --- a/src/plugins/bineditor/bineditor.h +++ b/src/plugins/bineditor/bineditor.h @@ -108,7 +108,6 @@ public: Core::IEditor *editor() const { return m_ieditor; } void setEditor(Core::IEditor *ieditor) { m_ieditor = ieditor; } - bool hasSelection() const { return m_cursorPosition != m_anchorPosition; } int selectionStart() const { return qMin(m_anchorPosition, m_cursorPosition); } int selectionEnd() const { return qMax(m_anchorPosition, m_cursorPosition); } diff --git a/src/plugins/clearcase/clearcasecontrol.cpp b/src/plugins/clearcase/clearcasecontrol.cpp index c1497f979a..1fc377a584 100644 --- a/src/plugins/clearcase/clearcasecontrol.cpp +++ b/src/plugins/clearcase/clearcasecontrol.cpp @@ -57,6 +57,10 @@ Core::Id ClearCaseControl::id() const bool ClearCaseControl::isConfigured() const { +#ifdef WITH_TESTS + if (m_plugin->isFakeCleartool()) + return true; +#endif const QString binary = m_plugin->settings().ccBinaryPath; if (binary.isEmpty()) return false; diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 3afb4d2fff..bc9750c61b 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -48,6 +48,7 @@ #include <coreplugin/documentmanager.h> #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/icore.h> +#include <coreplugin/infobar.h> #include <coreplugin/messagemanager.h> #include <coreplugin/mimedatabase.h> #include <coreplugin/progressmanager/progressmanager.h> @@ -186,6 +187,9 @@ ClearCasePlugin::ClearCasePlugin() : m_submitActionTriggered(false), m_activityMutex(new QMutex), m_statusMap(new StatusMap) + #ifdef WITH_TESTS + ,m_fakeClearTool(false) + #endif { qRegisterMetaType<ClearCase::Internal::FileStatus::Status>("ClearCase::Internal::FileStatus::Status"); } @@ -230,12 +234,82 @@ QString ClearCasePlugin::getDriveLetterOfPath(const QString &directory) { // cdUp until we get just the drive letter QDir dir(directory); - while (dir.cdUp()) + while (!dir.isRoot() && dir.cdUp()) { } return dir.path(); } +void ClearCasePlugin::updateStatusForFile(const QString &absFile) +{ + setStatus(absFile, getFileStatus(absFile), false); +} + +/// Give warning if a derived object is edited +void ClearCasePlugin::updateEditDerivedObjectWarning(const QString &fileName, + const FileStatus::Status status) +{ + if (!isDynamic()) + return; + + Core::IDocument *curDocument = Core::EditorManager::currentDocument(); + if (!curDocument) + return; + + Core::InfoBar *infoBar = curDocument->infoBar(); + const Core::Id derivedObjectWarning("ClearCase.DerivedObjectWarning"); + + if (status == FileStatus::Derived) { + if (!infoBar->canInfoBeAdded(derivedObjectWarning)) + return; + + infoBar->addInfo(Core::InfoBarEntry(derivedObjectWarning, + tr("Editing Derived Object: %1") + .arg(fileName))); + } else { + infoBar->removeInfo(derivedObjectWarning); + } +} + +FileStatus::Status ClearCasePlugin::getFileStatus(const QString &fileName) const +{ + QTC_CHECK(!fileName.isEmpty()); + + const QDir viewRootDir = QFileInfo(fileName).dir(); + const QString viewRoot = viewRootDir.path(); + + QStringList args(QLatin1String("ls")); + args << fileName; + QString buffer = runCleartoolSync(viewRoot, args); + + const int atatpos = buffer.indexOf(QLatin1String("@@")); + if (atatpos != -1) { // probably a managed file + const QString absFile = + viewRootDir.absoluteFilePath( + QDir::fromNativeSeparators(buffer.left(atatpos))); + QTC_CHECK(QFile(absFile).exists()); + QTC_CHECK(!absFile.isEmpty()); + + // "cleartool ls" of a derived object looks like this: + // /path/to/file/export/MyFile.h@@--11-13T19:52.266580 + const QChar c = buffer.at(atatpos + 2); + const bool isDerivedObject = c != QLatin1Char('/') && c != QLatin1Char('\\'); + if (isDerivedObject) + return FileStatus::Derived; + + // find first whitespace. anything before that is not interesting + const int wspos = buffer.indexOf(QRegExp(QLatin1String("\\s"))); + if (buffer.lastIndexOf(QLatin1String("CHECKEDOUT"), wspos) != -1) + return FileStatus::CheckedOut; + else + return FileStatus::CheckedIn; + } else { + QTC_CHECK(QFile(fileName).exists()); + QTC_CHECK(!fileName.isEmpty()); + return FileStatus::NotManaged; + } +} + /// /// Check if the directory is managed by ClearCase. /// @@ -483,12 +557,14 @@ bool ClearCasePlugin::initialize(const QStringList & /*arguments */, QString *er clearcaseMenu->addSeparator(globalcontext); m_diffActivityAction = new QAction(tr("Diff A&ctivity..."), this); + m_diffActivityAction->setEnabled(false); command = ActionManager::registerAction(m_diffActivityAction, CMD_ID_DIFF_ACTIVITY, globalcontext); connect(m_diffActivityAction, SIGNAL(triggered()), this, SLOT(diffActivity())); clearcaseMenu->addAction(command); m_commandLocator->appendCommand(command); m_checkInActivityAction = new Utils::ParameterAction(tr("Ch&eck In Activity"), tr("Chec&k In Activity \"%1\"..."), Utils::ParameterAction::EnabledWithParameter, this); + m_checkInActivityAction->setEnabled(false); command = ActionManager::registerAction(m_checkInActivityAction, CMD_ID_CHECKIN_ACTIVITY, globalcontext); connect(m_checkInActivityAction, SIGNAL(triggered()), this, SLOT(startCheckInActivity())); command->setAttribute(Command::CA_UpdateText); @@ -671,7 +747,16 @@ QStringList ClearCasePlugin::ccGetActiveVobs() const return res; } -// file must be relative to topLevel, and using '/' path separator +void ClearCasePlugin::checkAndReIndexUnknownFile(const QString &file) +{ + if (isDynamic()) { + // reindex unknown files + if (m_statusMap->value(file, FileStatus(FileStatus::Unknown)).status == FileStatus::Unknown) + updateStatusForFile(file); + } +} + +// file must be absolute, and using '/' path separator FileStatus ClearCasePlugin::vcsStatus(const QString &file) const { return m_statusMap->value(file, FileStatus(FileStatus::Unknown)); @@ -727,7 +812,10 @@ void ClearCasePlugin::updateStatusActions() bool hasFile = currentState().hasFile(); if (hasFile) { QString absoluteFileName = currentState().currentFile(); - fileStatus = m_statusMap->value(absoluteFileName, FileStatus(FileStatus::Unknown)); + checkAndReIndexUnknownFile(absoluteFileName); + fileStatus = vcsStatus(absoluteFileName); + + updateEditDerivedObjectWarning(absoluteFileName, fileStatus.status); if (Constants::debug) qDebug() << Q_FUNC_INFO << absoluteFileName << ", status = " @@ -771,6 +859,7 @@ void ClearCasePlugin::updateActions(VcsBase::VcsBasePlugin::ActionState as) m_annotateCurrentAction->setParameter(fileName); m_addFileAction->setParameter(fileName); m_updateIndexAction->setEnabled(!m_settings.disableIndexer); + updateStatusActions(); } @@ -791,6 +880,7 @@ void ClearCasePlugin::addCurrentFile() // Set the FileStatus of file given in absolute path void ClearCasePlugin::setStatus(const QString &file, FileStatus::Status status, bool update) { + QTC_CHECK(!file.isEmpty()); m_statusMap->insert(file, FileStatus(status, QFileInfo(file).permissions())); if (update && currentState().currentFile() == file) @@ -929,7 +1019,7 @@ void ClearCasePlugin::ccDiffWithPred(const QString &workingDir, const QStringLis if ((m_settings.diffType == GraphicalDiff) && (files.count() == 1)) { const QString file = files.first(); const QString absFilePath = workingDir + QLatin1Char('/') + file; - if (m_statusMap->value(absFilePath).status == FileStatus::Hijacked) + if (vcsStatus(absFilePath).status == FileStatus::Hijacked) diffGraphical(ccGetFileVersion(workingDir, file), file); else diffGraphical(file); @@ -943,7 +1033,7 @@ void ClearCasePlugin::ccDiffWithPred(const QString &workingDir, const QStringLis QString result; foreach (const QString &file, files) { const QString absFilePath = workingDir + QLatin1Char('/') + file; - if (m_statusMap->value(QDir::fromNativeSeparators(absFilePath)).status == FileStatus::Hijacked) + if (vcsStatus(QDir::fromNativeSeparators(absFilePath)).status == FileStatus::Hijacked) result += diffExternal(ccGetFileVersion(workingDir, file), file); else result += diffExternal(file); @@ -1235,7 +1325,8 @@ void ClearCasePlugin::viewStatus() m_viewData = ccGetView(m_topLevel); QTC_ASSERT(!m_viewData.name.isEmpty() && !m_settings.disableIndexer, return); VcsBase::VcsBaseOutputWindow *outputwindow = VcsBase::VcsBaseOutputWindow::instance(); - outputwindow->appendCommand(QLatin1String("Indexed files status (C=Checked Out, H=Hijacked, ?=Missing)")); + outputwindow->appendCommand(QLatin1String("Indexed files status (C=Checked Out, " + "H=Hijacked, ?=Missing)")); bool anymod = false; for (StatusMap::ConstIterator it = m_statusMap->constBegin(); it != m_statusMap->constEnd(); @@ -1481,14 +1572,14 @@ bool ClearCasePlugin::vcsOpen(const QString &workingDir, const QString &fileName CheckOutDialog coDialog(title, m_viewData.isUcm); if (!m_settings.disableIndexer && - (fi.isWritable() || m_statusMap->value(absPath).status == FileStatus::Unknown)) + (fi.isWritable() || vcsStatus(absPath).status == FileStatus::Unknown)) QtConcurrent::run(&sync, QStringList(absPath)).waitForFinished(); - if (m_statusMap->value(absPath).status == FileStatus::CheckedOut) { + if (vcsStatus(absPath).status == FileStatus::CheckedOut) { QMessageBox::information(0, tr("ClearCase Checkout"), tr("File is already checked out.")); return true; } // Only snapshot views can have hijacked files - bool isHijacked = (!m_viewData.isDynamic && (m_statusMap->value(absPath).status & FileStatus::Hijacked)); + bool isHijacked = (!m_viewData.isDynamic && (vcsStatus(absPath).status & FileStatus::Hijacked)); if (!isHijacked) coDialog.hideHijack(); if (coDialog.exec() == QDialog::Accepted) { @@ -1760,7 +1851,13 @@ QString ClearCasePlugin::vcsGetRepositoryURL(const QString & /*directory*/) /// bool ClearCasePlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) const { +#ifdef WITH_TESTS + // If running with tests and fake ClearTool is enabled, then pretend we manage every directory + QString topLevelFound = m_fakeClearTool ? directory : findTopLevel(directory); +#else QString topLevelFound = findTopLevel(directory); +#endif + if (topLevel) *topLevel = topLevelFound; return !topLevelFound.isEmpty(); @@ -1877,9 +1974,9 @@ bool ClearCasePlugin::ccCheckUcm(const QString &viewname, const QString &working bool ClearCasePlugin::managesFile(const QString &workingDirectory, const QString &fileName) const { - QStringList args; - args << QLatin1String("ls") << fileName; - return runCleartoolSync(workingDirectory, args).contains(QLatin1String("@@")); + QString absFile = QFileInfo(QDir(workingDirectory), fileName).absoluteFilePath(); + const FileStatus::Status status = getFileStatus(absFile); + return status != FileStatus::NotManaged && status != FileStatus::Derived; } ViewData ClearCasePlugin::ccGetView(const QString &workingDir) const @@ -2142,6 +2239,233 @@ void ClearCasePlugin::testLogResolving() "src/plugins/clearcase/clearcaseeditor.h@@/main/branch1/branch2/9", "src/plugins/clearcase/clearcaseeditor.h@@/main/branch1/branch2/8"); } + +void ClearCasePlugin::initTestCase() +{ + m_tempFile = QDir::currentPath() + QLatin1String("/cc_file.cpp"); + Utils::FileSaver srcSaver(m_tempFile); + srcSaver.write(QByteArray()); + srcSaver.finalize(); +} + +void ClearCasePlugin::cleanupTestCase() +{ + QVERIFY(QFile::remove(m_tempFile)); +} + +void ClearCasePlugin::testFileStatusParsing_data() +{ + QTest::addColumn<QString>("filename"); + QTest::addColumn<QString>("cleartoolLsLine"); + QTest::addColumn<int>("status"); + + QTest::newRow("CheckedOut") + << m_tempFile + << QString(m_tempFile + QLatin1String("@@/main/branch1/CHECKEDOUT from /main/branch1/0 Rule: CHECKEDOUT")) + << static_cast<int>(FileStatus::CheckedOut); + + QTest::newRow("CheckedIn") + << m_tempFile + << QString(m_tempFile + QLatin1String("@@/main/9 Rule: MY_LABEL_1.6.4 [-mkbranch branch1]")) + << static_cast<int>(FileStatus::CheckedIn); + + QTest::newRow("Hijacked") + << m_tempFile + << QString(m_tempFile + QLatin1String("@@/main/9 [hijacked] Rule: MY_LABEL_1.5.33 [-mkbranch myview1]")) + << static_cast<int>(FileStatus::Hijacked); + + + QTest::newRow("Missing") + << m_tempFile + << QString(m_tempFile + QLatin1String("@@/main/9 [loaded but missing] Rule: MY_LABEL_1.5.33 [-mkbranch myview1]")) + << static_cast<int>(FileStatus::Missing); +} + +void ClearCasePlugin::testFileStatusParsing() +{ + ClearCasePlugin *plugin = ClearCasePlugin::instance(); + plugin->m_statusMap = QSharedPointer<StatusMap>(new StatusMap); + + QFETCH(QString, filename); + QFETCH(QString, cleartoolLsLine); + QFETCH(int, status); + + ClearCaseSync ccSync(plugin, plugin->m_statusMap); + ccSync.verifyParseStatus(filename, cleartoolLsLine, static_cast<FileStatus::Status>(status)); +} + +void ClearCasePlugin::testFileNotManaged() +{ + ClearCasePlugin *plugin = ClearCasePlugin::instance(); + plugin->m_statusMap = QSharedPointer<StatusMap>(new StatusMap); + ClearCaseSync ccSync(plugin, plugin->m_statusMap); + ccSync.verifyFileNotManaged(); +} + +void ClearCasePlugin::testFileCheckedOutDynamicView() +{ + ClearCasePlugin *plugin = ClearCasePlugin::instance(); + plugin->m_statusMap = QSharedPointer<StatusMap>(new StatusMap); + + ClearCaseSync ccSync(plugin, plugin->m_statusMap); + ccSync.verifyFileCheckedOutDynamicView(); +} + +void ClearCasePlugin::testFileCheckedInDynamicView() +{ + ClearCasePlugin *plugin = ClearCasePlugin::instance(); + plugin->m_statusMap = QSharedPointer<StatusMap>(new StatusMap); + ClearCaseSync ccSync(plugin, plugin->m_statusMap); + ccSync.verifyFileCheckedInDynamicView(); +} + +void ClearCasePlugin::testFileNotManagedDynamicView() +{ + ClearCasePlugin *plugin = ClearCasePlugin::instance(); + plugin->m_statusMap = QSharedPointer<StatusMap>(new StatusMap); + ClearCaseSync ccSync(plugin, plugin->m_statusMap); + ccSync.verifyFileNotManagedDynamicView(); +} + +namespace { +/** + * @brief Convenience class which also properly cleans up editors and temp files + */ +class TestCase +{ +public: + TestCase(const QString &fileName) : + m_fileName(fileName) , + m_editor(0) + { + ClearCasePlugin::instance()->setFakeCleartool(true); + Utils::FileSaver srcSaver(fileName); + srcSaver.write(QByteArray()); + srcSaver.finalize(); + + m_editor = Core::EditorManager::openEditor(fileName); + + QCoreApplication::processEvents(); // process any pending events + } + + ViewData dummyViewData() const + { + ViewData viewData; + viewData.name = QLatin1String("fake_view"); + viewData.root = QDir::currentPath(); + viewData.isUcm = false; + return viewData; + } + + ~TestCase() + { + Core::EditorManager::closeEditor(m_editor, false); + QCoreApplication::processEvents(); // process any pending events + + QFile file(m_fileName); + if (!file.isWritable()) // Windows can't delete read only files + file.setPermissions(file.permissions() | QFile::WriteUser); + QVERIFY(file.remove()); + ClearCasePlugin::instance()->setFakeCleartool(false); + } + +private: + QString m_fileName; + Core::IEditor *m_editor; +}; +} + +void ClearCasePlugin::testStatusActions_data() +{ + QTest::addColumn<int>("status"); + QTest::addColumn<bool>("checkOutAction"); + QTest::addColumn<bool>("undoCheckOutAction"); + QTest::addColumn<bool>("undoHijackAction"); + QTest::addColumn<bool>("checkInCurrentAction"); + QTest::addColumn<bool>("addFileAction"); + QTest::addColumn<bool>("checkInActivityAction"); + QTest::addColumn<bool>("diffActivityAction"); + + QTest::newRow("Unknown") << static_cast<int>(FileStatus::Unknown) + << true << true << true << true << true << false << false; + QTest::newRow("CheckedOut") << static_cast<int>(FileStatus::CheckedOut) + << false << true << false << true << false << false << false; + QTest::newRow("CheckedIn") << static_cast<int>(FileStatus::CheckedIn) + << true << false << false << false << false << false << false; + QTest::newRow("NotManaged") << static_cast<int>(FileStatus::NotManaged) + << false << false << false << false << true << false << false; +} + +void ClearCasePlugin::testStatusActions() +{ + const QString fileName = QDir::currentPath() + QLatin1String("/clearcase_file.cpp"); + TestCase testCase(fileName); + + m_viewData = testCase.dummyViewData(); + + QFETCH(int, status); + FileStatus::Status tempStatus = static_cast<FileStatus::Status>(status); + + // special case: file should appear as "Unknown" since there is no entry in the index + // and we don't want to explicitly set the status for this test case + if (tempStatus != FileStatus::Unknown) + setStatus(fileName, tempStatus, true); + + QFETCH(bool, checkOutAction); + QFETCH(bool, undoCheckOutAction); + QFETCH(bool, undoHijackAction); + QFETCH(bool, checkInCurrentAction); + QFETCH(bool, addFileAction); + QFETCH(bool, checkInActivityAction); + QFETCH(bool, diffActivityAction); + + QCOMPARE(m_checkOutAction->isEnabled(), checkOutAction); + QCOMPARE(m_undoCheckOutAction->isEnabled(), undoCheckOutAction); + QCOMPARE(m_undoHijackAction->isEnabled(), undoHijackAction); + QCOMPARE(m_checkInCurrentAction->isEnabled(), checkInCurrentAction); + QCOMPARE(m_addFileAction->isEnabled(), addFileAction); + QCOMPARE(m_checkInActivityAction->isEnabled(), checkInActivityAction); + QCOMPARE(m_diffActivityAction->isEnabled(), diffActivityAction); +} + +void ClearCasePlugin::testVcsStatusDynamicReadonlyNotManaged() +{ + // File is not in map, and is read-only + ClearCasePlugin::instance(); + m_statusMap = QSharedPointer<StatusMap>(new StatusMap); + + const QString fileName = QDir::currentPath() + QLatin1String("/readonly_notmanaged_file.cpp"); + + m_viewData.isDynamic = true; + TestCase testCase(fileName); + + QFile::setPermissions(fileName, QFile::ReadOwner | + QFile::ReadUser | + QFile::ReadGroup | + QFile::ReadOther); + + m_viewData = testCase.dummyViewData(); + m_viewData.isDynamic = true; + + QCOMPARE(vcsStatus(fileName).status, FileStatus::NotManaged); + +} + +void ClearCasePlugin::testVcsStatusDynamicNotManaged() +{ + ClearCasePlugin::instance(); + m_statusMap = QSharedPointer<StatusMap>(new StatusMap); + + const QString fileName = QDir::currentPath() + QLatin1String("/notmanaged_file.cpp"); + + m_viewData.isDynamic = true; + TestCase testCase(fileName); + + m_viewData = testCase.dummyViewData(); + m_viewData.isDynamic = true; + + QCOMPARE(vcsStatus(fileName).status, FileStatus::NotManaged); +} #endif } // namespace Internal diff --git a/src/plugins/clearcase/clearcaseplugin.h b/src/plugins/clearcase/clearcaseplugin.h index 929844197a..3f263e67f6 100644 --- a/src/plugins/clearcase/clearcaseplugin.h +++ b/src/plugins/clearcase/clearcaseplugin.h @@ -89,7 +89,8 @@ public: CheckedOut = 0x02, Hijacked = 0x04, NotManaged = 0x08, - Missing = 0x10 + Missing = 0x10, + Derived = 0x20 } status; QFile::Permissions permissions; @@ -158,6 +159,7 @@ public: bool ccFileOp(const QString &workingDir, const QString &title, const QStringList &args, const QString &fileName, const QString &file2 = QString()); FileStatus vcsStatus(const QString &file) const; + void checkAndReIndexUnknownFile(const QString &file); QString currentView() const { return m_viewData.name; } QString viewRoot() const { return m_viewData.root; } void refreshActivities(); @@ -167,6 +169,10 @@ public: bool ccCheckUcm(const QString &viewname, const QString &workingDir) const; bool managesFile(const QString &workingDirectory, const QString &fileName) const; +#ifdef WITH_TESTS + inline void setFakeCleartool(const bool b = true) { m_fakeClearTool = b; } + inline bool isFakeCleartool() const { return m_fakeClearTool; } +#endif public slots: void vcsAnnotate(const QString &workingDir, const QString &file, @@ -199,9 +205,21 @@ private slots: void closing(); void updateStatusActions(); #ifdef WITH_TESTS + void initTestCase(); + void cleanupTestCase(); void testDiffFileResolving_data(); void testDiffFileResolving(); void testLogResolving(); + void testFileStatusParsing_data(); + void testFileStatusParsing(); + void testFileNotManaged(); + void testFileCheckedOutDynamicView(); + void testFileCheckedInDynamicView(); + void testFileNotManagedDynamicView(); + void testStatusActions_data(); + void testStatusActions(); + void testVcsStatusDynamicReadonlyNotManaged(); + void testVcsStatusDynamicNotManaged(); #endif protected: @@ -244,6 +262,10 @@ private: int timeOut, QTextCodec *outputCodec = 0); static QString getDriveLetterOfPath(const QString &directory); + FileStatus::Status getFileStatus(const QString &fileName) const; + void updateStatusForFile(const QString &absFile); + void updateEditDerivedObjectWarning(const QString &fileName, const FileStatus::Status status); + ClearCaseSettings m_settings; QString m_checkInMessageFileName; @@ -282,6 +304,10 @@ private: QSharedPointer<StatusMap> m_statusMap; static ClearCasePlugin *m_clearcasePluginInstance; +#ifdef WITH_TESTS + bool m_fakeClearTool; + QString m_tempFile; +#endif }; } // namespace Internal diff --git a/src/plugins/clearcase/clearcasesync.cpp b/src/plugins/clearcase/clearcasesync.cpp index ac965eec93..769c4707bd 100644 --- a/src/plugins/clearcase/clearcasesync.cpp +++ b/src/plugins/clearcase/clearcasesync.cpp @@ -34,6 +34,12 @@ #include <QFutureInterface> #include <QProcess> #include <QStringList> +#include <utils/qtcassert.h> + +#ifdef WITH_TESTS +#include <QTest> +#include <utils/fileutils.h> +#endif namespace ClearCase { namespace Internal { @@ -44,60 +50,108 @@ ClearCaseSync::ClearCaseSync(ClearCasePlugin *plugin, QSharedPointer<StatusMap> { } -void ClearCaseSync::run(QFutureInterface<void> &future, QStringList &files) +QStringList ClearCaseSync::updateStatusHotFiles(const QString &viewRoot, int &total) { - ClearCaseSettings settings = m_plugin->settings(); - const QString program = settings.ccBinaryPath; - if (program.isEmpty()) - return; - int total = files.size(); - const bool hot = (total < 10); - int processed = 0; - QString view = m_plugin->currentView(); - if (view.isEmpty()) - emit updateStreamAndView(); - if (!hot) - total = settings.totalFiles.value(view, total); + QStringList hotFiles; + // find all files whose permissions changed OR hijacked files + // (might have become checked out) + const StatusMap::Iterator send = m_statusMap->end(); + for (StatusMap::Iterator it = m_statusMap->begin(); it != send; ++it) { + const QFileInfo fi(viewRoot, it.key()); + const bool permChanged = it.value().permissions != fi.permissions(); + if (permChanged || it.value().status == FileStatus::Hijacked) { + hotFiles.append(it.key()); + it.value().status = FileStatus::Unknown; + ++total; + } + } + return hotFiles; +} - // refresh activities list - if (m_plugin->isUcm()) - m_plugin->refreshActivities(); +// Set status for all files to unknown until we're done indexing +void ClearCaseSync::invalidateStatus(const QDir &viewRootDir, + const QStringList &files) +{ + foreach (const QString &file, files) { + m_plugin->setStatus(viewRootDir.absoluteFilePath(file), FileStatus::Unknown, false); + } +} - if (settings.disableIndexer) +void ClearCaseSync::invalidateStatusAllFiles() +{ + const StatusMap::ConstIterator send = m_statusMap->end(); + for (StatusMap::ConstIterator it = m_statusMap->begin(); it != send; ++it) + m_plugin->setStatus(it.key(), FileStatus::Unknown, false); +} + +void ClearCaseSync::processCleartoolLsLine(const QDir &viewRootDir, const QString &buffer) +{ + const int atatpos = buffer.indexOf(QLatin1String("@@")); + + if (atatpos == -1) return; - const bool isDynamic = m_plugin->isDynamic(); + // find first whitespace. anything before that is not interesting + const int wspos = buffer.indexOf(QRegExp(QLatin1String("\\s"))); + const QString absFile = + viewRootDir.absoluteFilePath( + QDir::fromNativeSeparators(buffer.left(atatpos))); + QTC_CHECK(QFile(absFile).exists()); + QTC_CHECK(!absFile.isEmpty()); + + QString ccState; + const QRegExp reState(QLatin1String("^\\s*\\[[^\\]]*\\]")); // [hijacked]; [loaded but missing] + if (reState.indexIn(buffer, wspos + 1, QRegExp::CaretAtOffset) != -1) { + ccState = reState.cap(); + if (ccState.indexOf(QLatin1String("hijacked")) != -1) + m_plugin->setStatus(absFile, FileStatus::Hijacked, true); + else if (ccState.indexOf(QLatin1String("loaded but missing")) != -1) + m_plugin->setStatus(absFile, FileStatus::Missing, false); + } + else if (buffer.lastIndexOf(QLatin1String("CHECKEDOUT"), wspos) != -1) + m_plugin->setStatus(absFile, FileStatus::CheckedOut, true); + // don't care about checked-in files not listed in project + else if (m_statusMap->contains(absFile)) + m_plugin->setStatus(absFile, FileStatus::CheckedIn, true); +} + +void ClearCaseSync::updateTotalFilesCount(const QString view, ClearCaseSettings settings, + const int processed) +{ + settings = m_plugin->settings(); // Might have changed while task was running + settings.totalFiles[view] = processed; + m_plugin->setSettings(settings); +} + +void ClearCaseSync::updateStatusForNotManagedFiles(const QStringList &files) +{ + foreach (const QString &file, files) { + QString absFile = QFileInfo(file).absoluteFilePath(); + if (!m_statusMap->contains(absFile)) + m_plugin->setStatus(absFile, FileStatus::NotManaged, false); + } +} + +void ClearCaseSync::syncSnapshotView(QFutureInterface<void> &future, QStringList &files, + const ClearCaseSettings &settings) +{ + QString view = m_plugin->currentView(); + + int totalFileCount = files.size(); + const bool hot = (totalFileCount < 10); + int processed = 0; + if (!hot) + totalFileCount = settings.totalFiles.value(view, totalFileCount); + const QString viewRoot = m_plugin->viewRoot(); const QDir viewRootDir(viewRoot); QStringList args(QLatin1String("ls")); if (hot) { - // find all files whose permissions changed OR hijacked files - // (might have become checked out) - const StatusMap::Iterator send = m_statusMap->end(); - for (StatusMap::Iterator it = m_statusMap->begin(); it != send; ++it) { - const QFileInfo fi(viewRoot, it.key()); - const bool permChanged = it.value().permissions != fi.permissions(); - if (permChanged || it.value().status == FileStatus::Hijacked) { - files.append(it.key()); - it.value().status = FileStatus::Unknown; - ++total; - } else if (isDynamic && !fi.isWritable()) { // assume a read only file is checked in - it.value().status = FileStatus::CheckedIn; - ++total; - } - } + files << updateStatusHotFiles(viewRoot, totalFileCount); args << files; } else { - foreach (const QString &file, files) { - if (isDynamic) { // assume a read only file is checked in - const QFileInfo fi(viewRootDir, file); - if (!fi.isWritable()) - m_plugin->setStatus(fi.absoluteFilePath(), FileStatus::CheckedIn, false); - } else { - m_plugin->setStatus(viewRootDir.absoluteFilePath(file), FileStatus::Unknown, false); - } - } + invalidateStatus(viewRootDir, files); args << QLatin1String("-recurse"); QStringList vobs; @@ -111,10 +165,12 @@ void ClearCaseSync::run(QFutureInterface<void> &future, QStringList &files) // adding 1 for initial sync in which total is not accurate, to prevent finishing // (we don't want it to become green) - future.setProgressRange(0, total + 1); + future.setProgressRange(0, totalFileCount + 1); QProcess process; process.setWorkingDirectory(viewRoot); + const QString program = settings.ccBinaryPath; + process.start(program, args); if (!process.waitForStarted()) return; @@ -124,55 +180,208 @@ void ClearCaseSync::run(QFutureInterface<void> &future, QStringList &files) process.bytesAvailable() && !future.isCanceled()) { const QString line = QString::fromLocal8Bit(process.readLine().constData()); - buffer += line; if (buffer.endsWith(QLatin1Char('\n')) || process.atEnd()) { - const int atatpos = buffer.indexOf(QLatin1String("@@")); - if (atatpos != -1) { // probably managed file - // find first whitespace. anything before that is not interesting - const int wspos = buffer.indexOf(QRegExp(QLatin1String("\\s"))); - const QString absFile = - viewRootDir.absoluteFilePath( - QDir::fromNativeSeparators(buffer.left(atatpos))); - - QString ccState; - const QRegExp reState(QLatin1String("^\\s*\\[[^\\]]*\\]")); // [hijacked]; [loaded but missing] - if (reState.indexIn(buffer, wspos + 1, QRegExp::CaretAtOffset) != -1) { - ccState = reState.cap(); - if (ccState.indexOf(QLatin1String("hijacked")) != -1) - m_plugin->setStatus(absFile, FileStatus::Hijacked, true); - else if (ccState.indexOf(QLatin1String("loaded but missing")) != -1) - m_plugin->setStatus(absFile, FileStatus::Missing, false); - } - else if (buffer.lastIndexOf(QLatin1String("CHECKEDOUT"), wspos) != -1) - m_plugin->setStatus(absFile, FileStatus::CheckedOut, true); - // don't care about checked-in files not listed in project - else if (m_statusMap->contains(absFile)) - m_plugin->setStatus(absFile, FileStatus::CheckedIn, true); - } + processCleartoolLsLine(viewRootDir, buffer); buffer.clear(); - future.setProgressValue(qMin(total, ++processed)); + future.setProgressValue(qMin(totalFileCount, ++processed)); } } } if (!future.isCanceled()) { - foreach (const QString &file, files) { - QString absFile = QFileInfo(file).absoluteFilePath(); - if (!m_statusMap->contains(absFile)) - m_plugin->setStatus(absFile, FileStatus::NotManaged, false); - } - future.setProgressValue(total + 1); - if (!hot) { - settings = m_plugin->settings(); // Might have changed while task was running - settings.totalFiles[view] = processed; - m_plugin->setSettings(settings); + updateStatusForNotManagedFiles(files); + future.setProgressValue(totalFileCount + 1); + if (!hot) + updateTotalFilesCount(view, settings, processed); + } + + if (process.state() == QProcess::Running) + process.kill(); + + process.waitForFinished(); +} + +void ClearCaseSync::processCleartoolLscheckoutLine(const QString &buffer) +{ + QString absFile = buffer.trimmed(); + m_plugin->setStatus(absFile, FileStatus::CheckedOut, true); +} + +/// +/// Update the file status for dynamic views. +/// +void ClearCaseSync::syncDynamicView(QFutureInterface<void> &future, + const ClearCaseSettings& settings) +{ + // Always invalidate status for all files + invalidateStatusAllFiles(); + + QStringList args(QLatin1String("lscheckout")); + args << QLatin1String("-avobs") + << QLatin1String("-me") + << QLatin1String("-cview") + << QLatin1String("-s"); + + const QString viewRoot = m_plugin->viewRoot(); + + QProcess process; + process.setWorkingDirectory(viewRoot); + + const QString program = settings.ccBinaryPath; + process.start(program, args); + if (!process.waitForStarted()) + return; + + QString buffer; + int processed = 0; + while (process.waitForReadyRead() && !future.isCanceled()) { + while (process.state() == QProcess::Running && + process.bytesAvailable() && !future.isCanceled()) { + const QString line = QString::fromLocal8Bit(process.readLine().constData()); + buffer += line; + if (buffer.endsWith(QLatin1Char('\n')) || process.atEnd()) { + processCleartoolLscheckoutLine(buffer); + buffer.clear(); + future.setProgressValue(++processed); + } } } + if (process.state() == QProcess::Running) process.kill(); + process.waitForFinished(); } +void ClearCaseSync::run(QFutureInterface<void> &future, QStringList &files) +{ + ClearCaseSettings settings = m_plugin->settings(); + if (settings.disableIndexer) + return; + + const QString program = settings.ccBinaryPath; + if (program.isEmpty()) + return; + + // refresh activities list + if (m_plugin->isUcm()) + m_plugin->refreshActivities(); + + QString view = m_plugin->currentView(); + if (view.isEmpty()) + emit updateStreamAndView(); + + if (m_plugin->isDynamic()) + syncDynamicView(future, settings); + else + syncSnapshotView(future, files, settings); +} + +#ifdef WITH_TESTS +namespace { +class TempFile +{ +public: + TempFile(const QString &fileName) + : m_fileName(fileName) + { + Utils::FileSaver srcSaver(fileName); + srcSaver.write(QByteArray()); + srcSaver.finalize(); + + } + + QString fileName() const { return m_fileName; } + + ~TempFile() + { + QVERIFY(QFile::remove(m_fileName)); + } + +private: + const QString m_fileName; +}; +} + +void ClearCaseSync::verifyParseStatus(const QString &fileName, + const QString &cleartoolLsLine, + const FileStatus::Status status) +{ + QCOMPARE(m_statusMap->count(), 0); + processCleartoolLsLine(QDir(QLatin1String("/")), cleartoolLsLine); + + if (status == FileStatus::CheckedIn) { + // The algorithm doesn't store checked in files in the index, unless it was there already + QCOMPARE(m_statusMap->count(), 0); + QCOMPARE(m_statusMap->contains(fileName), false); + m_plugin->setStatus(fileName, FileStatus::Unknown, false); + processCleartoolLsLine(QDir(QLatin1String("/")), cleartoolLsLine); + } + + QCOMPARE(m_statusMap->count(), 1); + QCOMPARE(m_statusMap->contains(fileName), true); + QCOMPARE(m_statusMap->value(fileName).status, status); + + QCOMPARE(m_statusMap->contains(QLatin1String(("notexisting"))), false); +} + +void ClearCaseSync::verifyFileNotManaged() +{ + QCOMPARE(m_statusMap->count(), 0); + TempFile temp(QDir::currentPath() + QLatin1String("/notmanaged.cpp")); + const QString fileName = temp.fileName(); + + updateStatusForNotManagedFiles(QStringList(fileName)); + + QCOMPARE(m_statusMap->count(), 1); + + QCOMPARE(m_statusMap->contains(fileName), true); + QCOMPARE(m_statusMap->value(fileName).status, FileStatus::NotManaged); +} + +void ClearCaseSync::verifyFileCheckedOutDynamicView() +{ + QCOMPARE(m_statusMap->count(), 0); + + QString fileName(QLatin1String("/hello.C")); + processCleartoolLscheckoutLine(fileName); + + QCOMPARE(m_statusMap->count(), 1); + + QVERIFY(m_statusMap->contains(fileName)); + QCOMPARE(m_statusMap->value(fileName).status, FileStatus::CheckedOut); + + QVERIFY(!m_statusMap->contains(QLatin1String(("notexisting")))); +} + +void ClearCaseSync::verifyFileCheckedInDynamicView() +{ + QCOMPARE(m_statusMap->count(), 0); + + QString fileName(QLatin1String("/hello.C")); + + // checked in files are not kept in the index + QCOMPARE(m_statusMap->count(), 0); + QCOMPARE(m_statusMap->contains(fileName), false); +} + +void ClearCaseSync::verifyFileNotManagedDynamicView() +{ + QCOMPARE(m_statusMap->count(), 0); + TempFile temp(QDir::currentPath() + QLatin1String("/notmanaged.cpp")); + const QString fileName = temp.fileName(); + + updateStatusForNotManagedFiles(QStringList(fileName)); + + QCOMPARE(m_statusMap->count(), 1); + + QVERIFY(m_statusMap->contains(fileName)); + QCOMPARE(m_statusMap->value(fileName).status, FileStatus::NotManaged); +} + +#endif + + } // namespace Internal } // namespace ClearCase diff --git a/src/plugins/clearcase/clearcasesync.h b/src/plugins/clearcase/clearcasesync.h index 31b109a3c9..1a4e4f9f77 100644 --- a/src/plugins/clearcase/clearcasesync.h +++ b/src/plugins/clearcase/clearcasesync.h @@ -42,12 +42,38 @@ public: explicit ClearCaseSync(ClearCasePlugin *plugin, QSharedPointer<StatusMap> statusMap); void run(QFutureInterface<void> &future, QStringList &files); + QStringList updateStatusHotFiles(const QString &viewRoot, int &total); + void invalidateStatus(const QDir &viewRootDir, const QStringList &files); + void invalidateStatusAllFiles(); + void processCleartoolLsLine(const QDir &viewRootDir, const QString &buffer); + void updateTotalFilesCount(const QString view, ClearCaseSettings settings, const int processed); + void updateStatusForNotManagedFiles(const QStringList &files); + + void syncDynamicView(QFutureInterface<void> &future, + const ClearCaseSettings &settings); + void syncSnapshotView(QFutureInterface<void> &future, QStringList &files, + const ClearCaseSettings &settings); + + void processCleartoolLscheckoutLine(const QString &buffer); signals: void updateStreamAndView(); private: ClearCasePlugin *m_plugin; QSharedPointer<StatusMap> m_statusMap; + +public slots: +#ifdef WITH_TESTS + void verifyParseStatus(const QString &fileName, const QString &cleartoolLsLine, + const FileStatus::Status); + void verifyFileNotManaged(); + + void verifyFileCheckedOutDynamicView(); + void verifyFileCheckedInDynamicView(); + void verifyFileNotManagedDynamicView(); + +#endif + }; } // namespace Internal diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 8708272914..e2adb85a99 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -350,7 +350,7 @@ bool CMakeProject::parseCMakeLists() // This explicitly adds -I. to the include paths part->includePaths += projectDirectory(); part->includePaths += cbpparser.includeFiles(); - part->defines += cbpparser.defines(); + part->projectDefines += cbpparser.defines(); CppTools::ProjectFileAdder adder(part->files); foreach (const QString &file, m_files) diff --git a/src/plugins/cmakeprojectmanager/makestep.cpp b/src/plugins/cmakeprojectmanager/makestep.cpp index 5059965132..59db213396 100644 --- a/src/plugins/cmakeprojectmanager/makestep.cpp +++ b/src/plugins/cmakeprojectmanager/makestep.cpp @@ -90,7 +90,7 @@ void MakeStep::ctor() { m_percentProgress = QRegExp(QLatin1String("^\\[\\s*(\\d*)%\\]")); m_ninjaProgress = QRegExp(QLatin1String("^\\[\\s*(\\d*)/\\s*(\\d*)")); - m_ninjaProgressString = QLatin1String("[%s/%t "); // ninja: [33/100 + m_ninjaProgressString = QLatin1String("[%f/%t "); // ninja: [33/100 //: Default display name for the cmake make step. setDefaultDisplayName(tr("Make")); diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp index 42fde01cea..c265adbba3 100644 --- a/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -382,7 +382,7 @@ void SettingsDialog::createGui() headerHLayout->addWidget(m_headerLabel); m_stackedLayout->setMargin(0); - m_stackedLayout->addWidget(new QWidget); // no category selected, for example when filtering + m_stackedLayout->addWidget(new QWidget(this)); // no category selected, for example when filtering QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Apply | diff --git a/src/plugins/coreplugin/editormanager/documentmodel.cpp b/src/plugins/coreplugin/editormanager/documentmodel.cpp index 737b2fc5fa..be48667591 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel.cpp +++ b/src/plugins/coreplugin/editormanager/documentmodel.cpp @@ -29,6 +29,7 @@ #include "documentmodel.h" #include "ieditor.h" +#include <coreplugin/documentmanager.h> #include <coreplugin/idocument.h> #include <utils/qtcassert.h> @@ -194,8 +195,9 @@ int DocumentModel::indexOfFilePath(const QString &filePath) const { if (filePath.isEmpty()) return -1; + const QString fixedPath = DocumentManager::fixFileName(filePath, DocumentManager::KeepLinks); for (int i = 0; i < d->m_documents.count(); ++i) { - if (d->m_documents.at(i)->fileName() == filePath) + if (DocumentManager::fixFileName(d->m_documents.at(i)->fileName(), DocumentManager::KeepLinks) == fixedPath) return i; } return -1; diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 253662a78f..ca62088313 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -1988,8 +1988,7 @@ void EditorManager::setupSaveActions(IDocument *document, QAction *saveAction, Q { saveAction->setEnabled(document != 0 && document->isModified()); saveAsAction->setEnabled(document != 0 && document->isSaveAsAllowed()); - revertToSavedAction->setEnabled(document != 0 - && !document->filePath().isEmpty() && document->isModified()); + revertToSavedAction->setEnabled(document != 0 && !document->filePath().isEmpty()); const QString documentName = document ? document->displayName() : QString(); QString quotedName; @@ -1998,7 +1997,9 @@ void EditorManager::setupSaveActions(IDocument *document, QAction *saveAction, Q quotedName = QLatin1Char('"') + documentName + QLatin1Char('"'); saveAction->setText(tr("&Save %1").arg(quotedName)); saveAsAction->setText(tr("Save %1 &As...").arg(quotedName)); - revertToSavedAction->setText(tr("Revert %1 to Saved").arg(quotedName)); + revertToSavedAction->setText(document->isModified() + ? tr("Revert %1 to Saved").arg(quotedName) + : tr("Reload %1").arg(quotedName)); } } diff --git a/src/plugins/coreplugin/editormanager/systemeditor.cpp b/src/plugins/coreplugin/editormanager/systemeditor.cpp index ef9cb8fec9..42336b277b 100644 --- a/src/plugins/coreplugin/editormanager/systemeditor.cpp +++ b/src/plugins/coreplugin/editormanager/systemeditor.cpp @@ -54,7 +54,7 @@ Id SystemEditor::id() const QString SystemEditor::displayName() const { - return QLatin1String("System Editor"); + return tr("System Editor"); } bool SystemEditor::startEditor(const QString &fileName, QString *errorMessage) diff --git a/src/plugins/coreplugin/editortoolbar.cpp b/src/plugins/coreplugin/editortoolbar.cpp index 536bd883f5..98706fdb6a 100644 --- a/src/plugins/coreplugin/editortoolbar.cpp +++ b/src/plugins/coreplugin/editortoolbar.cpp @@ -317,10 +317,12 @@ void EditorToolBar::listContextMenu(QPoint pos) DocumentModel::Entry *entry = EditorManager::documentModel()->documentAtRow( d->m_editorList->currentIndex()); QString fileName = entry ? entry->fileName() : QString(); - if (fileName.isEmpty()) + QString shortFileName = entry ? QFileInfo(fileName).fileName() : QString(); + if (fileName.isEmpty() || shortFileName.isEmpty()) return; QMenu menu; QAction *copyPath = menu.addAction(tr("Copy Full Path to Clipboard")); + QAction *copyFileName = menu.addAction(tr("Copy File Name to Clipboard")); menu.addSeparator(); EditorManager::addSaveAndCloseEditorActions(&menu, entry); menu.addSeparator(); @@ -328,6 +330,8 @@ void EditorToolBar::listContextMenu(QPoint pos) QAction *result = menu.exec(d->m_editorList->mapToGlobal(pos)); if (result == copyPath) QApplication::clipboard()->setText(QDir::toNativeSeparators(fileName)); + if (result == copyFileName) + QApplication::clipboard()->setText(shortFileName); } void EditorToolBar::makeEditorWritable() diff --git a/src/plugins/coreplugin/idocument.h b/src/plugins/coreplugin/idocument.h index 3178268389..7c8040e697 100644 --- a/src/plugins/coreplugin/idocument.h +++ b/src/plugins/coreplugin/idocument.h @@ -51,12 +51,6 @@ public: IgnoreAll = 2 }; - enum Utf8BomSetting { - AlwaysAdd = 0, - OnlyKeep = 1, - AlwaysDelete = 2 - }; - enum ChangeTrigger { TriggerInternal, TriggerExternal diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index b603dde306..839b3f1fcb 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -153,7 +153,7 @@ public: /*! * Called to get the version control repository root. */ - virtual QString vcsGetRepositoryURL(const QString &director) = 0; + virtual QString vcsGetRepositoryURL(const QString &directory) = 0; /*! * Topic (e.g. name of the current branch) diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 2bec68c320..6df8700c6e 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -482,11 +482,12 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption // painter->drawLine(rect.bottomLeft() + QPoint(1, 0), rect.bottomRight() - QPoint(1, 0)); QColor highlight(255, 255, 255, 30); painter->setPen(highlight); - } - else if (option->state & State_Enabled && - option->state & State_MouseOver) { + } else if (option->state & State_Enabled && option->state & State_MouseOver) { QColor lighter(255, 255, 255, 37); painter->fillRect(rect, lighter); + } else if (widget && widget->property("highlightWidget").toBool()) { + QColor shade(0, 0, 0, 128); + painter->fillRect(rect, shade); } if (option->state & State_HasFocus && (option->state & State_KeyboardFocusChange)) { QColor highlight = option->palette.highlight().color(); @@ -872,6 +873,8 @@ void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOpti QStyleOptionToolButton label = *toolbutton; label.palette = panelPalette(option->palette, lightColored(widget)); + if (widget && widget->property("highlightWidget").toBool()) + label.palette.setColor(QPalette::ButtonText, Qt::red); int fw = pixelMetric(PM_DefaultFrameWidth, option, widget); label.rect = button.adjusted(fw, fw, -fw, -fw); diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp index acfeb9145d..2d4789e9e5 100644 --- a/src/plugins/coreplugin/vcsmanager.cpp +++ b/src/plugins/coreplugin/vcsmanager.cpp @@ -196,7 +196,7 @@ VcsManager::~VcsManager() delete d; } -QObject *VcsManager::instance() +VcsManager *VcsManager::instance() { return m_instance; } @@ -233,8 +233,11 @@ IVersionControl* VcsManager::findVersionControlForDirectory(const QString &input { typedef QPair<QString, IVersionControl *> StringVersionControlPair; typedef QList<StringVersionControlPair> StringVersionControlPairs; - if (inputDirectory.isEmpty()) + if (inputDirectory.isEmpty()) { + if (topLevelDirectory) + topLevelDirectory->clear(); return 0; + } // Make sure we an absolute path: const QString directory = QDir(inputDirectory).absolutePath(); @@ -352,24 +355,6 @@ IVersionControl *VcsManager::checkout(const QString &versionControlType, return 0; } -bool VcsManager::findVersionControl(const QString &versionControlType) -{ - foreach (IVersionControl * versionControl, allVersionControls()) { - if (versionControl->displayName() == versionControlType) - return true; - } - return false; -} - -QString VcsManager::repositoryUrl(const QString &directory) -{ - IVersionControl *vc = findVersionControlForDirectory(directory); - - if (vc && vc->supportsOperation(Core::IVersionControl::GetRepositoryRootOperation)) - return vc->vcsGetRepositoryURL(directory); - return QString(); -} - bool VcsManager::promptToDelete(IVersionControl *vc, const QString &fileName) { QTC_ASSERT(vc, return true); diff --git a/src/plugins/coreplugin/vcsmanager.h b/src/plugins/coreplugin/vcsmanager.h index 6e76995b64..f346ac7638 100644 --- a/src/plugins/coreplugin/vcsmanager.h +++ b/src/plugins/coreplugin/vcsmanager.h @@ -58,23 +58,19 @@ class CORE_EXPORT VcsManager : public QObject Q_OBJECT public: - static QObject *instance(); + static VcsManager *instance(); static void extensionsInitialized(); static void resetVersionControlForDirectory(const QString &inputDirectory); static IVersionControl *findVersionControlForDirectory(const QString &directory, - QString *topLevelDirectory = 0); + QString *topLevelDirectory = 0); static QStringList repositories(const IVersionControl *); static IVersionControl *checkout(const QString &versionControlType, const QString &directory, const QByteArray &url); - // Used only by Trac plugin. - bool findVersionControl(const QString &versionControl); - // Used only by Trac plugin. - static QString repositoryUrl(const QString &directory); // Shows a confirmation dialog, whether the file should also be deleted // from revision control. Calls vcsDelete on the file. Returns false diff --git a/src/plugins/cpaster/cpasterplugin.cpp b/src/plugins/cpaster/cpasterplugin.cpp index 58020e6153..8878eb2dd2 100644 --- a/src/plugins/cpaster/cpasterplugin.cpp +++ b/src/plugins/cpaster/cpasterplugin.cpp @@ -211,7 +211,7 @@ void CodepasterPlugin::postEditor() if (ITextEditor *textEditor = qobject_cast<ITextEditor *>(editor)) { data = textEditor->selectedText(); if (data.isEmpty()) - data = textEditor->textDocument()->contents(); + data = textEditor->textDocument()->plainText(); mimeType = textEditor->document()->mimeType(); } } diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index f617545bd1..682adf61cc 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -717,6 +717,9 @@ void CPPEditorWidget::setMimeType(const QString &mt) = m_modelManager->cppEditorSupport(editor())->snapshotUpdater(); updater->setEditorDefines(additionalDirectives); + m_preprocessorButton->setProperty("highlightWidget", !additionalDirectives.trimmed().isEmpty()); + m_preprocessorButton->update(); + BaseTextEditorWidget::setMimeType(mt); setObjCEnabled(mt == QLatin1String(CppTools::Constants::OBJECTIVE_C_SOURCE_MIMETYPE) || mt == QLatin1String(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)); @@ -1995,8 +1998,12 @@ void CPPEditorWidget::showPreProcessorWidget() if (preProcessorDialog.exec() == QDialog::Accepted) { QSharedPointer<SnapshotUpdater> updater = m_modelManager->cppEditorSupport(editor())->snapshotUpdater(); - updater->setEditorDefines(preProcessorDialog.additionalPreProcessorDirectives().toUtf8()); + const QString &additionals = preProcessorDialog.additionalPreProcessorDirectives(); + updater->setEditorDefines(additionals.toUtf8()); updater->update(m_modelManager->workingCopy()); + + m_preprocessorButton->setProperty("highlightWidget", !additionals.trimmed().isEmpty()); + m_preprocessorButton->update(); } } diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h index 0989225538..e06355949b 100644 --- a/src/plugins/cppeditor/cppeditorplugin.h +++ b/src/plugins/cppeditor/cppeditorplugin.h @@ -97,6 +97,9 @@ private slots: void test_SwitchMethodDeclarationDefinition_data(); void test_SwitchMethodDeclarationDefinition(); + void test_FollowSymbolUnderCursor_multipleDocuments_data(); + void test_FollowSymbolUnderCursor_multipleDocuments(); + void test_FollowSymbolUnderCursor_data(); void test_FollowSymbolUnderCursor(); @@ -119,40 +122,19 @@ private slots: void test_doxygen_comments_data(); void test_doxygen_comments(); - void test_quickfix_CompleteSwitchCaseStatement_basic1(); - void test_quickfix_CompleteSwitchCaseStatement_basic2(); - void test_quickfix_CompleteSwitchCaseStatement_oneValueMissing(); - void test_quickfix_CompleteSwitchCaseStatement_QTCREATORBUG10366_1(); - void test_quickfix_CompleteSwitchCaseStatement_QTCREATORBUG10366_2(); + void test_quickfix_data(); + void test_quickfix(); - void test_quickfix_GenerateGetterSetter_basicGetterWithPrefix(); - void test_quickfix_GenerateGetterSetter_basicGetterWithPrefixAndNamespace(); void test_quickfix_GenerateGetterSetter_basicGetterWithPrefixAndNamespaceToCpp(); - void test_quickfix_GenerateGetterSetter_basicGetterWithoutPrefix(); - void test_quickfix_GenerateGetterSetter_customType(); - void test_quickfix_GenerateGetterSetter_constMember(); - void test_quickfix_GenerateGetterSetter_pointerToNonConst(); - void test_quickfix_GenerateGetterSetter_pointerToConst(); - void test_quickfix_GenerateGetterSetter_staticMember(); - void test_quickfix_GenerateGetterSetter_secondDeclarator(); - void test_quickfix_GenerateGetterSetter_triggeringRightAfterPointerSign(); - void test_quickfix_GenerateGetterSetter_notTriggeringOnMemberFunction(); - void test_quickfix_GenerateGetterSetter_notTriggeringOnMemberArray(); - void test_quickfix_GenerateGetterSetter_notTriggeringWhenGetterOrSetterExist(); - - void test_quickfix_ReformatPointerDeclaration(); - - void test_quickfix_InsertDefFromDecl_basic(); + void test_quickfix_InsertDefFromDecl_afterClass(); void test_quickfix_InsertDefFromDecl_headerSource_basic1(); void test_quickfix_InsertDefFromDecl_headerSource_basic2(); void test_quickfix_InsertDefFromDecl_headerSource_basic3(); void test_quickfix_InsertDefFromDecl_headerSource_namespace1(); void test_quickfix_InsertDefFromDecl_headerSource_namespace2(); - void test_quickfix_InsertDefFromDecl_freeFunction(); void test_quickfix_InsertDefFromDecl_insideClass(); void test_quickfix_InsertDefFromDecl_notTriggeringWhenDefinitionExists(); - void test_quickfix_InsertDefFromDecl_notTriggeringStatement(); void test_quickfix_InsertDefFromDecl_findRightImplementationFile(); void test_quickfix_InsertDefFromDecl_ignoreSurroundingGeneratedDeclarations(); void test_quickfix_InsertDefFromDecl_respectWsInOperatorNames1(); @@ -212,54 +194,18 @@ private slots: void test_quickfix_MoveFuncDefToDecl_CtorWithInitialization(); void test_quickfix_MoveFuncDefToDecl_structWithAssignedVariable(); - void test_quickfix_AssignToLocalVariable_freeFunction(); - void test_quickfix_AssignToLocalVariable_memberFunction(); - void test_quickfix_AssignToLocalVariable_staticMemberFunction(); - void test_quickfix_AssignToLocalVariable_newExpression(); void test_quickfix_AssignToLocalVariable_templates(); - void test_quickfix_AssignToLocalVariable_noInitializationList(); - void test_quickfix_AssignToLocalVariable_noVoidFunction(); - void test_quickfix_AssignToLocalVariable_noVoidMemberFunction(); - void test_quickfix_AssignToLocalVariable_noVoidStaticMemberFunction(); - void test_quickfix_AssignToLocalVariable_noFunctionInExpression(); - void test_quickfix_AssignToLocalVariable_noFunctionInFunction(); - void test_quickfix_AssignToLocalVariable_noReturnClass1(); - void test_quickfix_AssignToLocalVariable_noReturnClass2(); - void test_quickfix_AssignToLocalVariable_noReturnFunc1(); - void test_quickfix_AssignToLocalVariable_noReturnFunc2(); - void test_quickfix_AssignToLocalVariable_noSignatureMatch(); void test_quickfix_ExtractLiteralAsParameter_typeDeduction_data(); void test_quickfix_ExtractLiteralAsParameter_typeDeduction(); - void test_quickfix_ExtractLiteralAsParameter_freeFunction(); void test_quickfix_ExtractLiteralAsParameter_freeFunction_separateFiles(); - void test_quickfix_ExtractLiteralAsParameter_memberFunction(); void test_quickfix_ExtractLiteralAsParameter_memberFunction_separateFiles(); - void test_quickfix_ExtractLiteralAsParameter_memberFunctionInline(); - - void test_quickfix_InsertVirtualMethods_onlyDecl(); - void test_quickfix_InsertVirtualMethods_onlyDeclWithoutVirtual(); - void test_quickfix_InsertVirtualMethods_Access(); - void test_quickfix_InsertVirtualMethods_Superclass(); - void test_quickfix_InsertVirtualMethods_SuperclassOverride(); - void test_quickfix_InsertVirtualMethods_PureVirtualOnlyDecl(); - void test_quickfix_InsertVirtualMethods_PureVirtualInside(); - void test_quickfix_InsertVirtualMethods_inside(); - void test_quickfix_InsertVirtualMethods_outside(); + + void test_quickfix_InsertVirtualMethods_data(); + void test_quickfix_InsertVirtualMethods(); void test_quickfix_InsertVirtualMethods_implementationFile(); - void test_quickfix_InsertVirtualMethods_notrigger_allImplemented(); void test_quickfix_InsertVirtualMethods_BaseClassInNamespace(); - void test_quickfix_OptimizeForLoop_postcrement(); - void test_quickfix_OptimizeForLoop_condition(); - void test_quickfix_OptimizeForLoop_flipedCondition(); - void test_quickfix_OptimizeForLoop_alterVariableName(); - void test_quickfix_OptimizeForLoop_optimizeBoth(); - void test_quickfix_OptimizeForLoop_emptyInitializer(); - void test_quickfix_OptimizeForLoop_wrongInitializer(); - void test_quickfix_OptimizeForLoop_noTriggerNumeric1(); - void test_quickfix_OptimizeForLoop_noTriggerNumeric2(); - void test_functionhelper_virtualFunctions(); void test_functionhelper_virtualFunctions_data(); diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp index 208c21a5f4..6b566f9f41 100644 --- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp +++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp @@ -119,7 +119,7 @@ bool VirtualFunctionHelper::canLookupVirtualFunctionOverrides(Function *function { m_function = function; if (!m_function || !m_baseExpressionAST || !m_expressionDocument || !m_document || !m_scope - || m_scope->isClass() || m_snapshot.isEmpty()) { + || m_scope->isClass() || m_scope->isFunction() || m_snapshot.isEmpty()) { return false; } @@ -128,11 +128,13 @@ bool VirtualFunctionHelper::canLookupVirtualFunctionOverrides(Function *function if (IdExpressionAST *idExpressionAST = m_baseExpressionAST->asIdExpression()) { NameAST *name = idExpressionAST->name; const bool nameIsQualified = name && name->asQualifiedName(); - result = !nameIsQualified && FunctionHelper::isVirtualFunction(function, m_snapshot); + result = !nameIsQualified && FunctionHelper::isVirtualFunction( + function, LookupContext(m_document, m_snapshot)); } else if (MemberAccessAST *memberAccessAST = m_baseExpressionAST->asMemberAccess()) { NameAST *name = memberAccessAST->member_name; const bool nameIsQualified = name && name->asQualifiedName(); - if (!nameIsQualified && FunctionHelper::isVirtualFunction(function, m_snapshot)) { + if (!nameIsQualified && FunctionHelper::isVirtualFunction( + function, LookupContext(m_document, m_snapshot))) { TranslationUnit *unit = m_expressionDocument->translationUnit(); QTC_ASSERT(unit, return false); m_accessTokenKind = unit->tokenKind(memberAccessAST->access_token); @@ -242,6 +244,24 @@ Link findMacroLink(const QByteArray &name, const Document::Ptr &doc) return Link(); } +/// Considers also forward declared templates. +static bool isForwardClassDeclaration(Type *type) +{ + if (!type) + return false; + + if (type->isForwardClassDeclarationType()) { + return true; + } else if (Template *templ = type->asTemplateType()) { + if (Symbol *declaration = templ->declaration()) { + if (declaration->isForwardClassDeclaration()) + return true; + } + } + + return false; +} + inline LookupItem skipForwardDeclarations(const QList<LookupItem> &resolvedSymbols) { QList<LookupItem> candidates = resolvedSymbols; @@ -249,11 +269,11 @@ inline LookupItem skipForwardDeclarations(const QList<LookupItem> &resolvedSymbo LookupItem result = candidates.first(); const FullySpecifiedType ty = result.type().simplified(); - if (ty->isForwardClassDeclarationType()) { + if (isForwardClassDeclaration(ty.type())) { while (!candidates.isEmpty()) { LookupItem r = candidates.takeFirst(); - if (!r.type()->isForwardClassDeclarationType()) { + if (!isForwardClassDeclaration(r.type().type())) { result = r; break; } @@ -676,8 +696,15 @@ BaseTextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor & if (def == lastVisibleSymbol) def = 0; // jump to declaration then. - if (symbol->isForwardClassDeclaration()) + if (symbol->isForwardClassDeclaration()) { def = symbolFinder->findMatchingClassDeclaration(symbol, snapshot); + } else if (Template *templ = symbol->asTemplate()) { + if (Symbol *declaration = templ->declaration()) { + if (declaration->isForwardClassDeclaration()) + def = symbolFinder->findMatchingClassDeclaration(declaration, snapshot); + } + } + } link = m_widget->linkToSymbol(def ? def : symbol); diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index 55fad435e7..16e22817a5 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -60,6 +60,8 @@ using namespace TextEditor; namespace { +typedef QByteArray _; + class TestDocument; typedef QSharedPointer<TestDocument> TestDocumentPtr; @@ -349,10 +351,19 @@ private: } // anonymous namespace -/// Checks: All enum values are added as case statements for a blank switch. -void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_basic1() +typedef QSharedPointer<CppQuickFixFactory> CppQuickFixFactoryPtr; + +Q_DECLARE_METATYPE(CppQuickFixFactoryPtr) + +void CppEditorPlugin::test_quickfix_data() { - const QByteArray original = + QTest::addColumn<CppQuickFixFactoryPtr>("factory"); + QTest::addColumn<QByteArray>("original"); + QTest::addColumn<QByteArray>("expected"); + + // Checks: All enum values are added as case statements for a blank switch. + QTest::newRow("CompleteSwitchCaseStatement_basic1") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( "enum EnumType { V1, V2 };\n" "\n" "void f()\n" @@ -360,9 +371,8 @@ void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_basic1() " EnumType t;\n" " @switch (t) {\n" " }\n" - "}\n"; - ; - const QByteArray expected = + "}\n" + ) << _( "enum EnumType { V1, V2 };\n" "\n" "void f()\n" @@ -376,17 +386,11 @@ void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_basic1() " }\n" "}\n" "\n" - ; + ); - CompleteSwitchCaseStatement factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Checks: All enum values are added as case statements for a blank switch with a default case. -void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_basic2() -{ - const QByteArray original = + // Checks: All enum values are added as case statements for a blank switch with a default case. + QTest::newRow("CompleteSwitchCaseStatement_basic2") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( "enum EnumType { V1, V2 };\n" "\n" "void f()\n" @@ -396,9 +400,8 @@ void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_basic2() " default:\n" " break;\n" " }\n" - "}\n"; - ; - const QByteArray expected = + "}\n" + ) << _( "enum EnumType { V1, V2 };\n" "\n" "void f()\n" @@ -414,17 +417,11 @@ void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_basic2() " }\n" "}\n" "\n" - ; + ); - CompleteSwitchCaseStatement factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Checks: The missing enum value is added. -void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_oneValueMissing() -{ - const QByteArray original = + // Checks: The missing enum value is added. + QTest::newRow("CompleteSwitchCaseStatement_oneValueMissing") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( "enum EnumType { V1, V2 };\n" "\n" "void f()\n" @@ -436,9 +433,8 @@ void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_oneValueMissing( " default:\n" " break;\n" " }\n" - "}\n"; - ; - const QByteArray expected = + "}\n" + ) << _( "enum EnumType { V1, V2 };\n" "\n" "void f()\n" @@ -454,17 +450,11 @@ void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_oneValueMissing( " }\n" "}\n" "\n" - ; - - CompleteSwitchCaseStatement factory; - TestCase data(original, expected); - data.run(&factory); -} + ); -/// Checks: Find the correct enum type despite there being a declaration with the same name. -void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_QTCREATORBUG10366_1() -{ - const QByteArray original = + // Checks: Find the correct enum type despite there being a declaration with the same name. + QTest::newRow("CompleteSwitchCaseStatement_QTCREATORBUG10366_1") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( "enum test { TEST_1, TEST_2 };\n" "\n" "void f() {\n" @@ -472,8 +462,7 @@ void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_QTCREATORBUG1036 " @switch (test) {\n" " }\n" "}\n" - ; - const QByteArray expected = + ) << _( "enum test { TEST_1, TEST_2 };\n" "\n" "void f() {\n" @@ -486,17 +475,11 @@ void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_QTCREATORBUG1036 " }\n" "}\n" "\n" - ; - - CompleteSwitchCaseStatement factory; - TestCase data(original, expected); - data.run(&factory); -} + ); -/// Checks: Find the correct enum type despite there being a declaration with the same name. -void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_QTCREATORBUG10366_2() -{ - const QByteArray original = + // Checks: Find the correct enum type despite there being a declaration with the same name. + QTest::newRow("CompleteSwitchCaseStatement_QTCREATORBUG10366_2") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( "enum test1 { Wrong11, Wrong12 };\n" "enum test { Right1, Right2 };\n" "enum test2 { Wrong21, Wrong22 };\n" @@ -506,8 +489,7 @@ void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_QTCREATORBUG1036 " @switch (test) {\n" " }\n" "}\n" - ; - const QByteArray expected = + ) << _( "enum test1 { Wrong11, Wrong12 };\n" "enum test { Right1, Right2 };\n" "enum test2 { Wrong21, Wrong22 };\n" @@ -522,27 +504,20 @@ void CppEditorPlugin::test_quickfix_CompleteSwitchCaseStatement_QTCREATORBUG1036 " }\n" "}\n" "\n" - ; - - CompleteSwitchCaseStatement factory; - TestCase data(original, expected); - data.run(&factory); -} + ); -/// Checks: -/// 1. If the name does not start with ("m_" or "_") and does not -/// end with "_", we are forced to prefix the getter with "get". -/// 2. Setter: Use pass by value on integer/float and pointer types. -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_basicGetterWithPrefix() -{ - const QByteArray original = + // Checks: + // 1. If the name does not start with ("m_" or "_") and does not + // end with "_", we are forced to prefix the getter with "get". + // 2. Setter: Use pass by value on integer/float and pointer types. + QTest::newRow("GenerateGetterSetter_basicGetterWithPrefix") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( "\n" "class Something\n" "{\n" " int @it;\n" "};\n" - ; - const QByteArray expected = + ) << _( "\n" "class Something\n" "{\n" @@ -563,26 +538,19 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_basicGetterWithPrefix() " it = value;\n" "}\n" "\n" - ; + ); - GenerateGetterSetter factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Checks: In addition to test_quickfix_GenerateGetterSetter_basicGetterWithPrefix -/// generated definitions should fit in the namespace. -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_basicGetterWithPrefixAndNamespace() -{ - const QByteArray original = + // Checks: In addition to test_quickfix_GenerateGetterSetter_basicGetterWithPrefix + // generated definitions should fit in the namespace. + QTest::newRow("GenerateGetterSetter_basicGetterWithPrefixAndNamespace") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( "namespace SomeNamespace {\n" "class Something\n" "{\n" " int @it;\n" "};\n" - "}\n"; - - const QByteArray expected = + "}\n" + ) << _( "namespace SomeNamespace {\n" "class Something\n" "{\n" @@ -602,80 +570,20 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_basicGetterWithPrefixAn " it = value;\n" "}\n" "\n" - "}\n\n"; - - GenerateGetterSetter factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Checks: In addition to test_quickfix_GenerateGetterSetter_basicGetterWithPrefix -/// generated definitions should fit in the namespace. -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_basicGetterWithPrefixAndNamespaceToCpp() -{ - QList<TestDocumentPtr> testFiles; - QByteArray original; - QByteArray expected; - - // Header File - original = - "namespace SomeNamespace {\n" - "class Something\n" - "{\n" - " int @it;\n" - "};\n" - "}\n"; - expected = - "namespace SomeNamespace {\n" - "class Something\n" - "{\n" - " int it;\n" - "\n" - "public:\n" - " int getIt() const;\n" - " void setIt(int value);\n" - "};\n" - "}\n\n"; - testFiles << TestDocument::create(original, expected, QLatin1String("file.h")); - - // Source File - original = - "#include \"file.h\"\n" - "namespace SomeNamespace {\n" - "}\n"; - expected = - "#include \"file.h\"\n" - "namespace SomeNamespace {\n" - "int Something::getIt() const\n" - "{\n" - " return it;\n" - "}\n" - "\n" - "void Something::setIt(int value)\n" - "{\n" - " it = value;\n" "}\n\n" - "}\n\n"; - testFiles << TestDocument::create(original, expected, QLatin1String("file.cpp")); + ); - GenerateGetterSetter factory; - TestCase data(testFiles); - data.run(&factory); -} - -/// Checks: -/// 1. Getter: "get" prefix is not necessary. -/// 2. Setter: Parameter name is base name. -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_basicGetterWithoutPrefix() -{ - const QByteArray original = + // Checks: + // 1. Getter: "get" prefix is not necessary. + // 2. Setter: Parameter name is base name. + QTest::newRow("GenerateGetterSetter_basicGetterWithoutPrefix") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( "\n" "class Something\n" "{\n" " int @m_it;\n" "};\n" - ; - const QByteArray expected = + ) << _( "\n" "class Something\n" "{\n" @@ -696,25 +604,18 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_basicGetterWithoutPrefi " m_it = it;\n" "}\n" "\n" - ; - - GenerateGetterSetter factory; - TestCase data(original, expected); - data.run(&factory); -} + ); -/// Check: Setter: Use pass by reference for parameters which -/// are not integer, float or pointers. -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_customType() -{ - const QByteArray original = + // Check: Setter: Use pass by reference for parameters which + // are not integer, float or pointers. + QTest::newRow("GenerateGetterSetter_customType") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( "\n" "class Something\n" "{\n" " MyType @it;\n" "};\n" - ; - const QByteArray expected = + ) << _( "\n" "class Something\n" "{\n" @@ -735,26 +636,19 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_customType() " it = value;\n" "}\n" "\n" - ; + ); - GenerateGetterSetter factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Checks: -/// 1. Setter: No setter is generated for const members. -/// 2. Getter: Return a non-const type since it pass by value anyway. -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_constMember() -{ - const QByteArray original = + // Checks: + // 1. Setter: No setter is generated for const members. + // 2. Getter: Return a non-const type since it pass by value anyway. + QTest::newRow("GenerateGetterSetter_constMember") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( "\n" "class Something\n" "{\n" " const int @it;\n" "};\n" - ; - const QByteArray expected = + ) << _( "\n" "class Something\n" "{\n" @@ -769,24 +663,17 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_constMember() " return it;\n" "}\n" "\n" - ; - - GenerateGetterSetter factory; - TestCase data(original, expected); - data.run(&factory); -} + ); -/// Checks: No special treatment for pointer to non const. -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_pointerToNonConst() -{ - const QByteArray original = + // Checks: No special treatment for pointer to non const. + QTest::newRow("GenerateGetterSetter_pointerToNonConst") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( "\n" "class Something\n" "{\n" " int *it@;\n" "};\n" - ; - const QByteArray expected = + ) << _( "\n" "class Something\n" "{\n" @@ -807,24 +694,17 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_pointerToNonConst() " it = value;\n" "}\n" "\n" - ; - - GenerateGetterSetter factory; - TestCase data(original, expected); - data.run(&factory); -} + ); -/// Checks: No special treatment for pointer to const. -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_pointerToConst() -{ - const QByteArray original = + // Checks: No special treatment for pointer to const. + QTest::newRow("GenerateGetterSetter_pointerToConst") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( "\n" "class Something\n" "{\n" " const int *it@;\n" "};\n" - ; - const QByteArray expected = + ) << _( "\n" "class Something\n" "{\n" @@ -845,26 +725,19 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_pointerToConst() " it = value;\n" "}\n" "\n" - ; - - GenerateGetterSetter factory; - TestCase data(original, expected); - data.run(&factory); -} + ); -/// Checks: -/// 1. Setter: Setter is a static function. -/// 2. Getter: Getter is a static, non const function. -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_staticMember() -{ - const QByteArray original = + // Checks: + // 1. Setter: Setter is a static function. + // 2. Getter: Getter is a static, non const function. + QTest::newRow("GenerateGetterSetter_staticMember") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( "\n" "class Something\n" "{\n" " static int @m_member;\n" "};\n" - ; - const QByteArray expected = + ) << _( "\n" "class Something\n" "{\n" @@ -885,24 +758,17 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_staticMember() " m_member = member;\n" "}\n" "\n" - ; + ); - GenerateGetterSetter factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: Check if it works on the second declarator -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_secondDeclarator() -{ - const QByteArray original = + // Check: Check if it works on the second declarator + QTest::newRow("GenerateGetterSetter_secondDeclarator") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( "\n" "class Something\n" "{\n" " int *foo, @it;\n" "};\n" - ; - const QByteArray expected = + ) << _( "\n" "class Something\n" "{\n" @@ -923,24 +789,17 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_secondDeclarator() " it = value;\n" "}\n" "\n" - ; - - GenerateGetterSetter factory; - TestCase data(original, expected); - data.run(&factory); -} + ); -/// Check: Quick fix is offered for "int *@it;" ('@' denotes the text cursor position) -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_triggeringRightAfterPointerSign() -{ - const QByteArray original = + // Check: Quick fix is offered for "int *@it;" ('@' denotes the text cursor position) + QTest::newRow("GenerateGetterSetter_triggeringRightAfterPointerSign") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( "\n" "class Something\n" "{\n" " int *@it;\n" "};\n" - ; - const QByteArray expected = + ) << _( "\n" "class Something\n" "{\n" @@ -961,78 +820,498 @@ void CppEditorPlugin::test_quickfix_GenerateGetterSetter_triggeringRightAfterPoi " it = value;\n" "}\n" "\n" - ; + ); - GenerateGetterSetter factory; - TestCase data(original, expected); - data.run(&factory); -} + // Check: Quick fix is not triggered on a member function. + QTest::newRow("GenerateGetterSetter_notTriggeringOnMemberFunction") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) + << _("class Something { void @f(); };") << _(); -/// Check: Quick fix is not triggered on a member function. -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_notTriggeringOnMemberFunction() -{ - const QByteArray original = "class Something { void @f(); };"; + // Check: Quick fix is not triggered on an member array; + QTest::newRow("GenerateGetterSetter_notTriggeringOnMemberArray") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) + << _("class Something { void @a[10]; };") << _(); - GenerateGetterSetter factory; - TestCase data(original, original + "\n"); - data.run(&factory); -} - -/// Check: Quick fix is not triggered on an member array; -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_notTriggeringOnMemberArray() -{ - const QByteArray original = "class Something { void @a[10]; };"; - - GenerateGetterSetter factory; - TestCase data(original, original + "\n"); - data.run(&factory); -} - -/// Check: Do not offer the quick fix if there is already a member with the -/// getter or setter name we would generate. -void CppEditorPlugin::test_quickfix_GenerateGetterSetter_notTriggeringWhenGetterOrSetterExist() -{ - const QByteArray original = + // Check: Do not offer the quick fix if there is already a member with the + // getter or setter name we would generate. + QTest::newRow("GenerateGetterSetter_notTriggeringWhenGetterOrSetterExist") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( "class Something {\n" " int @it;\n" " void setIt();\n" - "};\n"; + "};\n" + ) << _(); - GenerateGetterSetter factory; - TestCase data(original, original + "\n"); - data.run(&factory); -} + QTest::newRow("MoveDeclarationOutOfIf_ifOnly") + << CppQuickFixFactoryPtr(new MoveDeclarationOutOfIf) << _( + "void f()\n" + "{\n" + " if (Foo *@foo = g())\n" + " h();\n" + "}\n" + ) << _( + "void f()\n" + "{\n" + " Foo *foo = g();\n" + " if (foo)\n" + " h();\n" + "}\n" + "\n" + ); -/// Check: Just a basic test since the main functionality is tested in -/// cpppointerdeclarationformatter_test.cpp -void CppEditorPlugin::test_quickfix_ReformatPointerDeclaration() -{ - const QByteArray original = "char@*s;"; - const QByteArray expected = "char *s;\n"; + QTest::newRow("MoveDeclarationOutOfIf_ifElse") + << CppQuickFixFactoryPtr(new MoveDeclarationOutOfIf) << _( + "void f()\n" + "{\n" + " if (Foo *@foo = g())\n" + " h();\n" + " else\n" + " i();\n" + "}\n" + ) << _( + "void f()\n" + "{\n" + " Foo *foo = g();\n" + " if (foo)\n" + " h();\n" + " else\n" + " i();\n" + "}\n" + "\n" + ); - ReformatPointerDeclaration factory; - TestCase data(original, expected); - data.run(&factory); -} + QTest::newRow("MoveDeclarationOutOfIf_ifElseIf") + << CppQuickFixFactoryPtr(new MoveDeclarationOutOfIf) << _( + "void f()\n" + "{\n" + " if (Foo *foo = g()) {\n" + " if (Bar *@bar = x()) {\n" + " h();\n" + " j();\n" + " }\n" + " } else {\n" + " i();\n" + " }\n" + "}\n" + ) << _( + "void f()\n" + "{\n" + " if (Foo *foo = g()) {\n" + " Bar *bar = x();\n" + " if (bar) {\n" + " h();\n" + " j();\n" + " }\n" + " } else {\n" + " i();\n" + " }\n" + "}\n" + "\n" + ); -/// Check from source file: If there is no header file, insert the definition after the class. -void CppEditorPlugin::test_quickfix_InsertDefFromDecl_basic() -{ - const QByteArray original = + QTest::newRow("MoveDeclarationOutOfWhile_singleWhile") + << CppQuickFixFactoryPtr(new MoveDeclarationOutOfWhile) << _( + "void f()\n" + "{\n" + " while (Foo *@foo = g())\n" + " j();\n" + "}\n" + ) << _( + "void f()\n" + "{\n" + " Foo *foo;\n" + " while ((foo = g()) != 0)\n" + " j();\n" + "}\n" + "\n" + ); + + QTest::newRow("MoveDeclarationOutOfWhile_whileInWhile") + << CppQuickFixFactoryPtr(new MoveDeclarationOutOfWhile) << _( + "void f()\n" + "{\n" + " while (Foo *foo = g()) {\n" + " while (Bar *@bar = h()) {\n" + " i();\n" + " j();\n" + " }\n" + " }\n" + "}\n" + ) << _( + "void f()\n" + "{\n" + " while (Foo *foo = g()) {\n" + " Bar *bar;\n" + " while ((bar = h()) != 0) {\n" + " i();\n" + " j();\n" + " }\n" + " }\n" + "}\n" + "\n" + ); + + // Check: Just a basic test since the main functionality is tested in + // cpppointerdeclarationformatter_test.cpp + QTest::newRow("ReformatPointerDeclaration") + << CppQuickFixFactoryPtr(new ReformatPointerDeclaration) + << _("char@*s;") + << _("char *s;\n"); + + // Check from source file: If there is no header file, insert the definition after the class. + QByteArray original = "struct Foo\n" "{\n" " Foo();@\n" "};\n"; - const QByteArray expected = original + + + QTest::newRow("InsertDefFromDecl_basic") + << CppQuickFixFactoryPtr(new InsertDefFromDecl) << original + << original + _( "\n" "\n" "Foo::Foo()\n" "{\n\n" "}\n" - "\n"; + "\n" + ); - InsertDefFromDecl factory; - TestCase data(original, expected); + QTest::newRow("InsertDefFromDecl_freeFunction") + << CppQuickFixFactoryPtr(new InsertDefFromDecl) + << _("void free()@;\n") + << _( + "void free()\n" + "{\n\n" + "}\n" + "\n" + ); + + // Check not triggering when it is a statement + QTest::newRow("InsertDefFromDecl_notTriggeringStatement") + << CppQuickFixFactoryPtr(new InsertDefFromDecl) << _( + "class Foo {\n" + "public:\n" + " Foo() {}\n" + "};\n" + "void freeFunc() {\n" + " Foo @f();" + "}\n" + ) << _(); + + // Check: Add local variable for a free function. + QTest::newRow("AssignToLocalVariable_freeFunction") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "int foo() {return 1;}\n" + "void bar() {fo@o();}" + ) << _( + "int foo() {return 1;}\n" + "void bar() {int localFoo = foo();}\n" + ); + + // Check: Add local variable for a member function. + QTest::newRow("AssignToLocalVariable_memberFunction") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "class Foo {public: int* fooFunc();}\n" + "void bar() {\n" + " Foo *f = new Foo;\n" + " @f->fooFunc();\n" + "}" + ) << _( + "class Foo {public: int* fooFunc();}\n" + "void bar() {\n" + " Foo *f = new Foo;\n" + " int *localFooFunc = f->fooFunc();\n" + "}\n" + ); + + // Check: Add local variable for a static member function. + QTest::newRow("AssignToLocalVariable_staticMemberFunction") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "class Foo {public: static int* fooFunc();}\n" + "void bar() {\n" + " Foo::fooF@unc();\n" + "}" + ) << _( + "class Foo {public: static int* fooFunc();}\n" + "void bar() {\n" + " int *localFooFunc = Foo::fooFunc();\n" + "}\n" + ); + + // Check: Add local variable for a new Expression. + QTest::newRow("AssignToLocalVariable_newExpression") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "class Foo {}\n" + "void bar() {\n" + " new Fo@o;\n" + "}" + ) << _( + "class Foo {}\n" + "void bar() {\n" + " Foo *localFoo = new Foo;\n" + "}\n" + ); + + // Check: No trigger for function inside member initialization list. + QTest::newRow("AssignToLocalVariable_noInitializationList") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "class Foo\n" + "{\n" + " public: Foo : m_i(fooF@unc()) {}\n" + " int fooFunc() {return 2;}\n" + " int m_i;\n" + "};" + ) << _(); + + // Check: No trigger for void functions. + QTest::newRow("AssignToLocalVariable_noVoidFunction") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "void foo() {}\n" + "void bar() {fo@o();}" + ) << _(); + + // Check: No trigger for void member functions. + QTest::newRow("AssignToLocalVariable_noVoidMemberFunction") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "class Foo {public: void fooFunc();}\n" + "void bar() {\n" + " Foo *f = new Foo;\n" + " @f->fooFunc();\n" + "}" + ) << _(); + + // Check: No trigger for void static member functions. + QTest::newRow("AssignToLocalVariable_noVoidStaticMemberFunction") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "class Foo {public: static void fooFunc();}\n" + "void bar() {\n" + " Foo::fo@oFunc();\n" + "}" + ) << _(); + + // Check: No trigger for functions in expressions. + QTest::newRow("AssignToLocalVariable_noFunctionInExpression") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "int foo(int a) {return a;}\n" + "int bar() {return 1;}" + "void baz() {foo(@bar() + bar());}" + ) << _(); + + // Check: No trigger for functions in functions. (QTCREATORBUG-9510) + QTest::newRow("AssignToLocalVariable_noFunctionInFunction") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "int foo(int a, int b) {return a + b;}\n" + "int bar(int a) {return a;}\n" + "void baz() {\n" + " int a = foo(ba@r(), bar());\n" + "}\n" + ) << _(); + + // Check: No trigger for functions in return statements (classes). + QTest::newRow("AssignToLocalVariable_noReturnClass1") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "class Foo {public: static void fooFunc();}\n" + "Foo* bar() {\n" + " return new Fo@o;\n" + "}" + ) << _(); + + // Check: No trigger for functions in return statements (classes). (QTCREATORBUG-9525) + QTest::newRow("AssignToLocalVariable_noReturnClass2") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "class Foo {public: int fooFunc();}\n" + "int bar() {\n" + " return (new Fo@o)->fooFunc();\n" + "}" + ) << _(); + + // Check: No trigger for functions in return statements (functions). + QTest::newRow("AssignToLocalVariable_noReturnFunc1") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "class Foo {public: int fooFunc();}\n" + "int bar() {\n" + " return Foo::fooFu@nc();\n" + "}" + ) << _(); + + // Check: No trigger for functions in return statements (functions). (QTCREATORBUG-9525) + QTest::newRow("AssignToLocalVariable_noReturnFunc2") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "int bar() {\n" + " return list.firs@t().foo;\n" + "}\n" + ) << _(); + + // Check: No trigger for functions which does not match in signature. + QTest::newRow("AssignToLocalVariable_noSignatureMatch") + << CppQuickFixFactoryPtr(new AssignToLocalVariable) << _( + "int someFunc(int);\n" + "\n" + "void f()\n" + "{\n" + " some@Func();\n" + "}" + ) << _(); + + QTest::newRow("ExtractLiteralAsParameter_freeFunction") + << CppQuickFixFactoryPtr(new ExtractLiteralAsParameter) << _( + "void foo(const char *a, long b = 1)\n" + "{return 1@56 + 123 + 156;}" + ) << _( + "void foo(const char *a, long b = 1, int newParameter = 156)\n" + "{return newParameter + 123 + newParameter;}\n" + ); + + QTest::newRow("ExtractLiteralAsParameter_memberFunction") + << CppQuickFixFactoryPtr(new ExtractLiteralAsParameter) << _( + "class Narf {\n" + "public:\n" + " int zort();\n" + "};\n\n" + "int Narf::zort()\n" + "{ return 15@5 + 1; }" + ) << _( + "class Narf {\n" + "public:\n" + " int zort(int newParameter = 155);\n" + "};\n\n" + "int Narf::zort(int newParameter)\n" + "{ return newParameter + 1; }\n" + ); + + QTest::newRow("ExtractLiteralAsParameter_memberFunctionInline") + << CppQuickFixFactoryPtr(new ExtractLiteralAsParameter) << _( + "class Narf {\n" + "public:\n" + " int zort()\n" + " { return 15@5 + 1; }\n" + "};" + ) << _( + "class Narf {\n" + "public:\n" + " int zort(int newParameter = 155)\n" + " { return newParameter + 1; }\n" + "};\n" + ); + + // Check: optimize postcrement + QTest::newRow("OptimizeForLoop_postcrement") + << CppQuickFixFactoryPtr(new OptimizeForLoop) + << _("void foo() {f@or (int i = 0; i < 3; i++) {}}\n") + << _("void foo() {for (int i = 0; i < 3; ++i) {}}\n\n"); + + // Check: optimize condition + QTest::newRow("OptimizeForLoop_condition") + << CppQuickFixFactoryPtr(new OptimizeForLoop) + << _("void foo() {f@or (int i = 0; i < 3 + 5; ++i) {}}\n") + << _("void foo() {for (int i = 0, total = 3 + 5; i < total; ++i) {}}\n\n"); + + // Check: optimize fliped condition + QTest::newRow("OptimizeForLoop_flipedCondition") + << CppQuickFixFactoryPtr(new OptimizeForLoop) + << _("void foo() {f@or (int i = 0; 3 + 5 > i; ++i) {}}\n") + << _("void foo() {for (int i = 0, total = 3 + 5; total > i; ++i) {}}\n\n"); + + // Check: if "total" used, create other name. + QTest::newRow("OptimizeForLoop_alterVariableName") + << CppQuickFixFactoryPtr(new OptimizeForLoop) + << _("void foo() {f@or (int i = 0, total = 0; i < 3 + 5; ++i) {}}\n") + << _("void foo() {for (int i = 0, total = 0, totalX = 3 + 5; i < totalX; ++i) {}}\n\n"); + + // Check: optimize postcrement and condition + QTest::newRow("OptimizeForLoop_optimizeBoth") + << CppQuickFixFactoryPtr(new OptimizeForLoop) + << _("void foo() {f@or (int i = 0; i < 3 + 5; i++) {}}\n") + << _("void foo() {for (int i = 0, total = 3 + 5; i < total; ++i) {}}\n\n"); + + // Check: empty initializier + QTest::newRow("OptimizeForLoop_emptyInitializer") + << CppQuickFixFactoryPtr(new OptimizeForLoop) + << _("int i; void foo() {f@or (; i < 3 + 5; ++i) {}}\n") + << _("int i; void foo() {for (int total = 3 + 5; i < total; ++i) {}}\n\n"); + + // Check: wrong initializier type -> no trigger + QTest::newRow("OptimizeForLoop_wrongInitializer") + << CppQuickFixFactoryPtr(new OptimizeForLoop) + << _("int i; void foo() {f@or (double a = 0; i < 3 + 5; ++i) {}}\n") + << _("int i; void foo() {f@or (double a = 0; i < 3 + 5; ++i) {}}\n\n"); + + // Check: No trigger when numeric + QTest::newRow("OptimizeForLoop_noTriggerNumeric1") + << CppQuickFixFactoryPtr(new OptimizeForLoop) + << _("void foo() {fo@r (int i = 0; i < 3; ++i) {}}\n") + << _(); + + // Check: No trigger when numeric + QTest::newRow("OptimizeForLoop_noTriggerNumeric2") + << CppQuickFixFactoryPtr(new OptimizeForLoop) + << _("void foo() {fo@r (int i = 0; i < -3; ++i) {}}\n") + << _(); +} + +void CppEditorPlugin::test_quickfix() +{ + QFETCH(CppQuickFixFactoryPtr, factory); + QFETCH(QByteArray, original); + QFETCH(QByteArray, expected); + + if (expected.isEmpty()) + expected = original + '\n'; + TestCase data(original, expected); + data.run(factory.data()); +} + +/// Checks: In addition to test_quickfix_GenerateGetterSetter_basicGetterWithPrefix +/// generated definitions should fit in the namespace. +void CppEditorPlugin::test_quickfix_GenerateGetterSetter_basicGetterWithPrefixAndNamespaceToCpp() +{ + QList<TestDocumentPtr> testFiles; + QByteArray original; + QByteArray expected; + + // Header File + original = + "namespace SomeNamespace {\n" + "class Something\n" + "{\n" + " int @it;\n" + "};\n" + "}\n"; + expected = + "namespace SomeNamespace {\n" + "class Something\n" + "{\n" + " int it;\n" + "\n" + "public:\n" + " int getIt() const;\n" + " void setIt(int value);\n" + "};\n" + "}\n\n"; + testFiles << TestDocument::create(original, expected, QLatin1String("file.h")); + + // Source File + original = + "#include \"file.h\"\n" + "namespace SomeNamespace {\n" + "}\n"; + expected = + "#include \"file.h\"\n" + "namespace SomeNamespace {\n" + "int Something::getIt() const\n" + "{\n" + " return it;\n" + "}\n" + "\n" + "void Something::setIt(int value)\n" + "{\n" + " it = value;\n" + "}\n\n" + "}\n\n"; + testFiles << TestDocument::create(original, expected, QLatin1String("file.cpp")); + + GenerateGetterSetter factory; + TestCase data(testFiles); data.run(&factory); } @@ -1261,21 +1540,6 @@ void CppEditorPlugin::test_quickfix_InsertDefFromDecl_headerSource_namespace2() data.run(&factory); } -void CppEditorPlugin::test_quickfix_InsertDefFromDecl_freeFunction() -{ - const QByteArray original = "void free()@;\n"; - const QByteArray expected = - "void free()\n" - "{\n\n" - "}\n" - "\n" - ; - - InsertDefFromDecl factory; - TestCase data(original, expected); - data.run(&factory); -} - /// Check definition insert inside class void CppEditorPlugin::test_quickfix_InsertDefFromDecl_insideClass() { @@ -1310,24 +1574,6 @@ void CppEditorPlugin::test_quickfix_InsertDefFromDecl_notTriggeringWhenDefinitio data.run(&factory, 1); } -/// Check not triggering when it is a statement -void CppEditorPlugin::test_quickfix_InsertDefFromDecl_notTriggeringStatement() -{ - const QByteArray original = - "class Foo {\n" - "public:\n" - " Foo() {}\n" - "};\n" - "void freeFunc() {\n" - " Foo @f();" - "}\n"; - const QByteArray expected = original + "\n"; - - InsertDefFromDecl factory; - TestCase data(original, expected); - data.run(&factory); -} - /// Find right implementation file. void CppEditorPlugin::test_quickfix_InsertDefFromDecl_findRightImplementationFile() { @@ -3253,80 +3499,6 @@ void CppEditorPlugin::test_quickfix_MoveFuncDefToDecl_structWithAssignedVariable data.run(&factory); } -/// Check: Add local variable for a free function. -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_freeFunction() -{ - const QByteArray original = - "int foo() {return 1;}\n" - "void bar() {fo@o();}"; - const QByteArray expected = - "int foo() {return 1;}\n" - "void bar() {int localFoo = foo();}\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: Add local variable for a member function. -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_memberFunction() -{ - const QByteArray original = - "class Foo {public: int* fooFunc();}\n" - "void bar() {\n" - " Foo *f = new Foo;\n" - " @f->fooFunc();\n" - "}"; - const QByteArray expected = - "class Foo {public: int* fooFunc();}\n" - "void bar() {\n" - " Foo *f = new Foo;\n" - " int *localFooFunc = f->fooFunc();\n" - "}\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: Add local variable for a static member function. -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_staticMemberFunction() -{ - const QByteArray original = - "class Foo {public: static int* fooFunc();}\n" - "void bar() {\n" - " Foo::fooF@unc();\n" - "}"; - const QByteArray expected = - "class Foo {public: static int* fooFunc();}\n" - "void bar() {\n" - " int *localFooFunc = Foo::fooFunc();\n" - "}\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: Add local variable for a new Expression. -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_newExpression() -{ - const QByteArray original = - "class Foo {}\n" - "void bar() {\n" - " new Fo@o;\n" - "}"; - const QByteArray expected = - "class Foo {}\n" - "void bar() {\n" - " Foo *localFoo = new Foo;\n" - "}\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - void CppEditorPlugin::test_quickfix_AssignToLocalVariable_templates() { @@ -3365,173 +3537,6 @@ void CppEditorPlugin::test_quickfix_AssignToLocalVariable_templates() data.run(&factory); } -/// Check: No trigger for function inside member initialization list. -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noInitializationList() -{ - const QByteArray original = - "class Foo\n" - "{\n" - " public: Foo : m_i(fooF@unc()) {}\n" - " int fooFunc() {return 2;}\n" - " int m_i;\n" - "};"; - const QByteArray expected = original + "\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger for void functions. -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noVoidFunction() -{ - const QByteArray original = - "void foo() {}\n" - "void bar() {fo@o();}"; - const QByteArray expected = original + "\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger for void member functions. -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noVoidMemberFunction() -{ - const QByteArray original = - "class Foo {public: void fooFunc();}\n" - "void bar() {\n" - " Foo *f = new Foo;\n" - " @f->fooFunc();\n" - "}"; - const QByteArray expected = original + "\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger for void static member functions. -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noVoidStaticMemberFunction() -{ - const QByteArray original = - "class Foo {public: static void fooFunc();}\n" - "void bar() {\n" - " Foo::fo@oFunc();\n" - "}"; - const QByteArray expected = original + "\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger for functions in expressions. -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noFunctionInExpression() -{ - const QByteArray original = - "int foo(int a) {return a;}\n" - "int bar() {return 1;}" - "void baz() {foo(@bar() + bar());}"; - const QByteArray expected = original + "\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger for functions in functions. (QTCREATORBUG-9510) -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noFunctionInFunction() -{ - const QByteArray original = - "int foo(int a, int b) {return a + b;}\n" - "int bar(int a) {return a;}\n" - "void baz() {\n" - " int a = foo(ba@r(), bar());\n" - "}\n"; - const QByteArray expected = original + "\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger for functions in return statements (classes). -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noReturnClass1() -{ - const QByteArray original = - "class Foo {public: static void fooFunc();}\n" - "Foo* bar() {\n" - " return new Fo@o;\n" - "}"; - const QByteArray expected = original + "\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger for functions in return statements (classes). (QTCREATORBUG-9525) -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noReturnClass2() -{ - const QByteArray original = - "class Foo {public: int fooFunc();}\n" - "int bar() {\n" - " return (new Fo@o)->fooFunc();\n" - "}"; - const QByteArray expected = original + "\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger for functions in return statements (functions). -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noReturnFunc1() -{ - const QByteArray original = - "class Foo {public: int fooFunc();}\n" - "int bar() {\n" - " return Foo::fooFu@nc();\n" - "}"; - const QByteArray expected = original + "\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger for functions in return statements (functions). (QTCREATORBUG-9525) -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noReturnFunc2() -{ - const QByteArray original = - "int bar() {\n" - " return list.firs@t().foo;\n" - "}\n"; - const QByteArray expected = original + "\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger for functions which does not match in signature. -void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noSignatureMatch() -{ - const QByteArray original = - "int someFunc(int);\n" - "\n" - "void f()\n" - "{\n" - " some@Func();\n" - "}"; - const QByteArray expected = original + "\n"; - - AssignToLocalVariable factory; - TestCase data(original, expected); - data.run(&factory); -} - void CppEditorPlugin::test_quickfix_ExtractLiteralAsParameter_typeDeduction_data() { QTest::addColumn<QByteArray>("typeString"); @@ -3597,20 +3602,6 @@ void CppEditorPlugin::test_quickfix_ExtractLiteralAsParameter_typeDeduction() data.run(&factory); } -void CppEditorPlugin::test_quickfix_ExtractLiteralAsParameter_freeFunction() -{ - const QByteArray original = - "void foo(const char *a, long b = 1)\n" - "{return 1@56 + 123 + 156;}"; - const QByteArray expected = - "void foo(const char *a, long b = 1, int newParameter = 156)\n" - "{return newParameter + 123 + newParameter;}\n"; - - ExtractLiteralAsParameter factory; - TestCase data(original, expected); - data.run(&factory); -} - void CppEditorPlugin::test_quickfix_ExtractLiteralAsParameter_freeFunction_separateFiles() { QList<TestDocumentPtr> testFiles; @@ -3638,28 +3629,6 @@ void CppEditorPlugin::test_quickfix_ExtractLiteralAsParameter_freeFunction_separ data.run(&factory); } -void CppEditorPlugin::test_quickfix_ExtractLiteralAsParameter_memberFunction() -{ - const QByteArray original = - "class Narf {\n" - "public:\n" - " int zort();\n" - "};\n\n" - "int Narf::zort()\n" - "{ return 15@5 + 1; }"; - const QByteArray expected = - "class Narf {\n" - "public:\n" - " int zort(int newParameter = 155);\n" - "};\n\n" - "int Narf::zort(int newParameter)\n" - "{ return newParameter + 1; }\n"; - - ExtractLiteralAsParameter factory; - TestCase data(original, expected); - data.run(&factory); -} - void CppEditorPlugin::test_quickfix_ExtractLiteralAsParameter_memberFunction_separateFiles() { QList<TestDocumentPtr> testFiles; @@ -3695,37 +3664,25 @@ void CppEditorPlugin::test_quickfix_ExtractLiteralAsParameter_memberFunction_sep data.run(&factory); } -void CppEditorPlugin::test_quickfix_ExtractLiteralAsParameter_memberFunctionInline() -{ - const QByteArray original = - "class Narf {\n" - "public:\n" - " int zort()\n" - " { return 15@5 + 1; }\n" - "};"; - const QByteArray expected = - "class Narf {\n" - "public:\n" - " int zort(int newParameter = 155)\n" - " { return newParameter + 1; }\n" - "};\n"; - - ExtractLiteralAsParameter factory; - TestCase data(original, expected); - data.run(&factory); -} +Q_DECLARE_METATYPE(InsertVirtualMethodsDialog::ImplementationMode) -/// Check: Insert only declarations -void CppEditorPlugin::test_quickfix_InsertVirtualMethods_onlyDecl() +void CppEditorPlugin::test_quickfix_InsertVirtualMethods_data() { - const QByteArray original = + QTest::addColumn<InsertVirtualMethodsDialog::ImplementationMode>("implementationMode"); + QTest::addColumn<bool>("insertVirtualKeyword"); + QTest::addColumn<QByteArray>("original"); + QTest::addColumn<QByteArray>("expected"); + + // Check: Insert only declarations + QTest::newRow("onlyDecl") + << InsertVirtualMethodsDialog::ModeOnlyDeclarations << true << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA();\n" "};\n\n" "class Derived : public Bas@eA {\n" - "};"; - const QByteArray expected = + "};" + ) << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA();\n" @@ -3735,25 +3692,19 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_onlyDecl() " // BaseA interface\n" "public:\n" " virtual int virtualFuncA();\n" - "};\n"; - - InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest( - InsertVirtualMethodsDialog::ModeOnlyDeclarations, true)); - TestCase data(original, expected); - data.run(&factory); -} + "};\n" + ); -/// Check: Insert only declarations vithout virtual keyword -void CppEditorPlugin::test_quickfix_InsertVirtualMethods_onlyDeclWithoutVirtual() -{ - const QByteArray original = + // Check: Insert only declarations vithout virtual keyword + QTest::newRow("onlyDeclWithoutVirtual") + << InsertVirtualMethodsDialog::ModeOnlyDeclarations << false << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA();\n" "};\n\n" "class Derived : public Bas@eA {\n" - "};"; - const QByteArray expected = + "};" + ) << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA();\n" @@ -3763,18 +3714,12 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_onlyDeclWithoutVirtual( " // BaseA interface\n" "public:\n" " int virtualFuncA();\n" - "};\n"; - - InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest( - InsertVirtualMethodsDialog::ModeOnlyDeclarations, false)); - TestCase data(original, expected); - data.run(&factory); -} + "};\n" + ); -/// Check: Are access specifiers considered -void CppEditorPlugin::test_quickfix_InsertVirtualMethods_Access() -{ - const QByteArray original = + // Check: Are access specifiers considered + QTest::newRow("Access") + << InsertVirtualMethodsDialog::ModeOnlyDeclarations << true << _( "class BaseA {\n" "public:\n" " virtual int a();\n" @@ -3792,8 +3737,8 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_Access() " virtual int g();\n" "};\n\n" "class Der@ived : public BaseA {\n" - "};"; - const QByteArray expected = + "};" + ) << _( "class BaseA {\n" "public:\n" " virtual int a();\n" @@ -3827,18 +3772,12 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_Access() " virtual int f();\n\n" "signals:\n" " virtual int g();\n" - "};\n"; - - InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest( - InsertVirtualMethodsDialog::ModeOnlyDeclarations, true)); - TestCase data(original, expected); - data.run(&factory); -} + "};\n" + ); -/// Check: Is a base class of a base class considered. -void CppEditorPlugin::test_quickfix_InsertVirtualMethods_Superclass() -{ - const QByteArray original = + // Check: Is a base class of a base class considered. + QTest::newRow("Superclass") + << InsertVirtualMethodsDialog::ModeOnlyDeclarations << true << _( "class BaseA {\n" "public:\n" " virtual int a();\n" @@ -3848,8 +3787,8 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_Superclass() " virtual int b();\n" "};\n\n" "class Der@ived : public BaseB {\n" - "};"; - const QByteArray expected = + "};" + ) << _( "class BaseA {\n" "public:\n" " virtual int a();\n" @@ -3867,18 +3806,12 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_Superclass() " // BaseA interface\n" "public:\n" " virtual int a();\n" - "};\n"; - - InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest( - InsertVirtualMethodsDialog::ModeOnlyDeclarations, true)); - TestCase data(original, expected); - data.run(&factory); -} + "};\n" + ); -/// Check: Do not insert reimplemented functions twice. -void CppEditorPlugin::test_quickfix_InsertVirtualMethods_SuperclassOverride() -{ - const QByteArray original = + // Check: Do not insert reimplemented functions twice. + QTest::newRow("SuperclassOverride") + << InsertVirtualMethodsDialog::ModeOnlyDeclarations << true << _( "class BaseA {\n" "public:\n" " virtual int a();\n" @@ -3888,8 +3821,8 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_SuperclassOverride() " virtual int a();\n" "};\n\n" "class Der@ived : public BaseB {\n" - "};"; - const QByteArray expected = + "};" + ) << _( "class BaseA {\n" "public:\n" " virtual int a();\n" @@ -3903,25 +3836,19 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_SuperclassOverride() " // BaseA interface\n" "public:\n" " virtual int a();\n" - "};\n"; - - InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest( - InsertVirtualMethodsDialog::ModeOnlyDeclarations, true)); - TestCase data(original, expected); - data.run(&factory); -} + "};\n" + ); -/// Check: Insert only declarations for pure virtual function -void CppEditorPlugin::test_quickfix_InsertVirtualMethods_PureVirtualOnlyDecl() -{ - const QByteArray original = + // Check: Insert only declarations for pure virtual function + QTest::newRow("PureVirtualOnlyDecl") + << InsertVirtualMethodsDialog::ModeOnlyDeclarations << true << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA() = 0;\n" "};\n\n" "class Derived : public Bas@eA {\n" - "};"; - const QByteArray expected = + "};" + ) << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA() = 0;\n" @@ -3931,25 +3858,19 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_PureVirtualOnlyDecl() " // BaseA interface\n" "public:\n" " virtual int virtualFuncA();\n" - "};\n"; - - InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest( - InsertVirtualMethodsDialog::ModeOnlyDeclarations, true)); - TestCase data(original, expected); - data.run(&factory); -} + "};\n" + ); -/// Check: Insert pure virtual functions inside class -void CppEditorPlugin::test_quickfix_InsertVirtualMethods_PureVirtualInside() -{ - const QByteArray original = + // Check: Insert pure virtual functions inside class + QTest::newRow("PureVirtualInside") + << InsertVirtualMethodsDialog::ModeInsideClass << true << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA() = 0;\n" "};\n\n" "class Derived : public Bas@eA {\n" - "};"; - const QByteArray expected = + "};" + ) << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA() = 0;\n" @@ -3961,25 +3882,19 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_PureVirtualInside() " virtual int virtualFuncA()\n" " {\n" " }\n" - "};\n"; - - InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest( - InsertVirtualMethodsDialog::ModeInsideClass, true)); - TestCase data(original, expected); - data.run(&factory); -} + "};\n" + ); -/// Check: Insert inside class -void CppEditorPlugin::test_quickfix_InsertVirtualMethods_inside() -{ - const QByteArray original = + // Check: Insert inside class + QTest::newRow("inside") + << InsertVirtualMethodsDialog::ModeInsideClass << true << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA();\n" "};\n\n" "class Derived : public Bas@eA {\n" - "};"; - const QByteArray expected = + "};" + ) << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA();\n" @@ -3991,25 +3906,19 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_inside() " virtual int virtualFuncA()\n" " {\n" " }\n" - "};\n"; - - InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest( - InsertVirtualMethodsDialog::ModeInsideClass, true)); - TestCase data(original, expected); - data.run(&factory); -} + "};\n" + ); -/// Check: Insert outside class -void CppEditorPlugin::test_quickfix_InsertVirtualMethods_outside() -{ - const QByteArray original = + // Check: Insert outside class + QTest::newRow("outside") + << InsertVirtualMethodsDialog::ModeOutsideClass << true << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA();\n" "};\n\n" "class Derived : public Bas@eA {\n" - "};"; - const QByteArray expected = + "};" + ) << _( "class BaseA {\n" "public:\n" " virtual int virtualFuncA();\n" @@ -4022,10 +3931,41 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_outside() "};\n\n" "int Derived::virtualFuncA()\n" "{\n" - "}\n"; + "}\n" + ); - InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest( - InsertVirtualMethodsDialog::ModeOutsideClass, true)); + // Check: No trigger: all implemented + QTest::newRow("notrigger_allImplemented") + << InsertVirtualMethodsDialog::ModeOutsideClass << true << _( + "class BaseA {\n" + "public:\n" + " virtual int virtualFuncA();\n" + "};\n\n" + "class Derived : public Bas@eA {\n" + "public:\n" + " virtual int virtualFuncA();\n" + "};" + ) << _( + "class BaseA {\n" + "public:\n" + " virtual int virtualFuncA();\n" + "};\n\n" + "class Derived : public Bas@eA {\n" + "public:\n" + " virtual int virtualFuncA();\n" + "};\n" + ); +} + +void CppEditorPlugin::test_quickfix_InsertVirtualMethods() +{ + QFETCH(InsertVirtualMethodsDialog::ImplementationMode, implementationMode); + QFETCH(bool, insertVirtualKeyword); + QFETCH(QByteArray, original); + QFETCH(QByteArray, expected); + + InsertVirtualMethods factory( + new InsertVirtualMethodsDialogTest(implementationMode, insertVirtualKeyword)); TestCase data(original, expected); data.run(&factory); } @@ -4077,34 +4017,6 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_implementationFile() data.run(&factory); } -/// Check: No trigger: all implemented -void CppEditorPlugin::test_quickfix_InsertVirtualMethods_notrigger_allImplemented() -{ - const QByteArray original = - "class BaseA {\n" - "public:\n" - " virtual int virtualFuncA();\n" - "};\n\n" - "class Derived : public Bas@eA {\n" - "public:\n" - " virtual int virtualFuncA();\n" - "};"; - const QByteArray expected = - "class BaseA {\n" - "public:\n" - " virtual int virtualFuncA();\n" - "};\n\n" - "class Derived : public Bas@eA {\n" - "public:\n" - " virtual int virtualFuncA();\n" - "};\n"; - - InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest( - InsertVirtualMethodsDialog::ModeOutsideClass, true)); - TestCase data(original, expected); - data.run(&factory); -} - /// Check: Qualified names. void CppEditorPlugin::test_quickfix_InsertVirtualMethods_BaseClassInNamespace() { @@ -4157,93 +4069,3 @@ void CppEditorPlugin::test_quickfix_InsertVirtualMethods_BaseClassInNamespace() TestCase data(testFiles); data.run(&factory); } - -/// Check: optimize postcrement -void CppEditorPlugin::test_quickfix_OptimizeForLoop_postcrement() -{ - const QByteArray original = "void foo() {f@or (int i = 0; i < 3; i++) {}}\n"; - const QByteArray expected = "void foo() {for (int i = 0; i < 3; ++i) {}}\n\n"; - OptimizeForLoop factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: optimize condition -void CppEditorPlugin::test_quickfix_OptimizeForLoop_condition() -{ - const QByteArray original = "void foo() {f@or (int i = 0; i < 3 + 5; ++i) {}}\n"; - const QByteArray expected = "void foo() {for (int i = 0, total = 3 + 5; i < total; ++i) {}}\n\n"; - OptimizeForLoop factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: optimize fliped condition -void CppEditorPlugin::test_quickfix_OptimizeForLoop_flipedCondition() -{ - const QByteArray original = "void foo() {f@or (int i = 0; 3 + 5 > i; ++i) {}}\n"; - const QByteArray expected = "void foo() {for (int i = 0, total = 3 + 5; total > i; ++i) {}}\n\n"; - OptimizeForLoop factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: if "total" used, create other name. -void CppEditorPlugin::test_quickfix_OptimizeForLoop_alterVariableName() -{ - const QByteArray original = "void foo() {f@or (int i = 0, total = 0; i < 3 + 5; ++i) {}}\n"; - const QByteArray expected = "void foo() {for (int i = 0, total = 0, totalX = 3 + 5; i < totalX; ++i) {}}\n\n"; - OptimizeForLoop factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: optimize postcrement and condition -void CppEditorPlugin::test_quickfix_OptimizeForLoop_optimizeBoth() -{ - const QByteArray original = "void foo() {f@or (int i = 0; i < 3 + 5; i++) {}}\n"; - const QByteArray expected = "void foo() {for (int i = 0, total = 3 + 5; i < total; ++i) {}}\n\n"; - OptimizeForLoop factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: empty initializier -void CppEditorPlugin::test_quickfix_OptimizeForLoop_emptyInitializer() -{ - const QByteArray original = "int i; void foo() {f@or (; i < 3 + 5; ++i) {}}\n"; - const QByteArray expected = "int i; void foo() {for (int total = 3 + 5; i < total; ++i) {}}\n\n"; - OptimizeForLoop factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: wrong initializier type -> no trigger -void CppEditorPlugin::test_quickfix_OptimizeForLoop_wrongInitializer() -{ - const QByteArray original = "int i; void foo() {f@or (double a = 0; i < 3 + 5; ++i) {}}\n"; - const QByteArray expected = "int i; void foo() {f@or (double a = 0; i < 3 + 5; ++i) {}}\n\n"; - OptimizeForLoop factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger when numeric -void CppEditorPlugin::test_quickfix_OptimizeForLoop_noTriggerNumeric1() -{ - const QByteArray original = "void foo() {fo@r (int i = 0; i < 3; ++i) {}}\n"; - const QByteArray expected = original + "\n"; - OptimizeForLoop factory; - TestCase data(original, expected); - data.run(&factory); -} - -/// Check: No trigger when numeric -void CppEditorPlugin::test_quickfix_OptimizeForLoop_noTriggerNumeric2() -{ - const QByteArray original = "void foo() {fo@r (int i = 0; i < -3; ++i) {}}\n"; - const QByteArray expected = original + "\n"; - OptimizeForLoop factory; - TestCase data(original, expected); - data.run(&factory); -} diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 46302c0200..0dcb161b8d 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -158,10 +158,8 @@ InsertionLocation insertLocationForMethodDefinition(Symbol *symbol, const bool u = locator.methodDefinition(symbol, useSymbolFinder, fileName); for (int i = 0; i < list.count(); ++i) { InsertionLocation location = list.at(i); - if (location.isValid() && location.fileName() == fileName) { + if (location.isValid() && location.fileName() == fileName) return location; - break; - } } // ...failed, @@ -774,6 +772,11 @@ public: setDescription(QApplication::translate("CppTools::QuickFix", "Move Declaration out of Condition")); + reset(); + } + + void reset() + { condition = mk.Condition(); pattern = mk.IfStatement(condition); } @@ -826,6 +829,8 @@ void MoveDeclarationOutOfIf::match(const CppQuickFixInterface &interface, result.append(op); return; } + + op->reset(); } } } @@ -841,7 +846,11 @@ public: { setDescription(QApplication::translate("CppTools::QuickFix", "Move Declaration out of Condition")); + reset(); + } + void reset() + { condition = mk.Condition(); pattern = mk.WhileStatement(condition); } @@ -903,6 +912,8 @@ void MoveDeclarationOutOfWhile::match(const CppQuickFixInterface &interface, result.append(op); return; } + + op->reset(); } } } @@ -4756,11 +4767,11 @@ public: ? Qt::Checked : Qt::Unchecked; for (Scope::iterator it = clazz->firstMember(); it != clazz->lastMember(); ++it) { if (const Function *func = (*it)->type()->asFunctionType()) { - if (!func->isVirtual()) + // Filter virtual destructors + if (func->name()->asDestructorNameId()) continue; - // Filter virtual destructors - if (printer.prettyName(func->name()).startsWith(QLatin1Char('~'))) + if (!func->isVirtual()) continue; // Filter OQbject's @@ -4904,16 +4915,12 @@ public: switch (spec) { case InsertionPointLocator::Private: return InsertionPointLocator::PrivateSlot; - break; case InsertionPointLocator::Protected: return InsertionPointLocator::ProtectedSlot; - break; case InsertionPointLocator::Public: return InsertionPointLocator::PublicSlot; - break; default: return spec; - break; } } return spec; diff --git a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp index 1e0f45334f..4530a47b98 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp +++ b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp @@ -210,52 +210,70 @@ IAssistProcessor *VirtualFunctionAssistProvider::createProcessor() const enum VirtualType { Virtual, PureVirtual }; static bool isVirtualFunction_helper(const Function *function, - const Snapshot &snapshot, - VirtualType virtualType) + const LookupContext &context, + VirtualType virtualType, + const Function **firstVirtual) { + enum { Unknown, False, True } res = Unknown; + + if (firstVirtual) + *firstVirtual = 0; + if (!function) return false; if (virtualType == PureVirtual) - return function->isPureVirtual(); - - if (function->isVirtual()) - return true; - - const QString filePath = QString::fromUtf8(function->fileName(), function->fileNameLength()); - if (Document::Ptr document = snapshot.document(filePath)) { - LookupContext context(document, snapshot); - QList<LookupItem> results = context.lookup(function->name(), function->enclosingScope()); - if (!results.isEmpty()) { - const bool isDestructor = function->name()->isDestructorNameId(); - foreach (const LookupItem &item, results) { - if (Symbol *symbol = item.declaration()) { - if (Function *functionType = symbol->type()->asFunctionType()) { - if (functionType->name()->isDestructorNameId() != isDestructor) - continue; - if (functionType == function) // already tested - continue; - if (functionType->isFinal()) - return false; - if (functionType->isVirtual()) + res = function->isPureVirtual() ? True : False; + + if (function->isVirtual()) { + if (firstVirtual) + *firstVirtual = function; + if (res == Unknown) + res = True; + } + + if (!firstVirtual && res != Unknown) + return res == True; + + QList<LookupItem> results = context.lookup(function->name(), function->enclosingScope()); + if (!results.isEmpty()) { + const bool isDestructor = function->name()->isDestructorNameId(); + foreach (const LookupItem &item, results) { + if (Symbol *symbol = item.declaration()) { + if (Function *functionType = symbol->type()->asFunctionType()) { + if (functionType->name()->isDestructorNameId() != isDestructor) + continue; + if (functionType == function) // already tested + continue; + if (functionType->isFinal()) + return res == True; + if (functionType->isVirtual()) { + if (!firstVirtual) return true; + if (res == Unknown) + res = True; + *firstVirtual = functionType; } } } } } - return false; + return res == True; } -bool FunctionHelper::isVirtualFunction(const Function *function, const Snapshot &snapshot) +bool FunctionHelper::isVirtualFunction(const Function *function, + const LookupContext &context, + const Function **firstVirtual) { - return isVirtualFunction_helper(function, snapshot, Virtual); + return isVirtualFunction_helper(function, context, Virtual, firstVirtual); } -bool FunctionHelper::isPureVirtualFunction(const Function *function, const Snapshot &snapshot) +bool FunctionHelper::isPureVirtualFunction(const Function *function, + const LookupContext &context, + const Function **firstVirtual) { - return isVirtualFunction_helper(function, snapshot, PureVirtual); + return isVirtualFunction_helper(function, context, PureVirtual, firstVirtual); } QList<Symbol *> FunctionHelper::overrides(Function *function, Class *functionsClass, @@ -324,6 +342,7 @@ typedef QList<Virtuality> VirtualityList; Q_DECLARE_METATYPE(CppEditor::Internal::Virtuality) Q_DECLARE_METATYPE(CppEditor::Internal::VirtualityList) +Q_DECLARE_METATYPE(QList<int>) namespace CppEditor { namespace Internal { @@ -333,33 +352,54 @@ void CppEditorPlugin::test_functionhelper_virtualFunctions() // Create and parse document QFETCH(QByteArray, source); QFETCH(VirtualityList, virtualityList); + QFETCH(QList<int>, firstVirtualList); Document::Ptr document = Document::create(QLatin1String("virtuals")); document->setUtf8Source(source); document->check(); // calls parse(); QCOMPARE(document->diagnosticMessages().size(), 0); QVERIFY(document->translationUnit()->ast()); + QList<const Function *> allFunctions; + const Function *firstVirtual = 0; // Iterate through Function symbols Snapshot snapshot; snapshot.insert(document); + const LookupContext context(document, snapshot); Control *control = document->translationUnit()->control(); Symbol **end = control->lastSymbol(); for (Symbol **it = control->firstSymbol(); it != end; ++it) { - const CPlusPlus::Symbol *symbol = *it; - if (const Function *function = symbol->asFunction()) { + if (const Function *function = (*it)->asFunction()) { + allFunctions.append(function); QTC_ASSERT(!virtualityList.isEmpty(), return); Virtuality virtuality = virtualityList.takeFirst(); - if (FunctionHelper::isVirtualFunction(function, snapshot)) { - if (FunctionHelper::isPureVirtualFunction(function, snapshot)) + QTC_ASSERT(!firstVirtualList.isEmpty(), return); + int firstVirtualIndex = firstVirtualList.takeFirst(); + bool isVirtual = FunctionHelper::isVirtualFunction(function, context, &firstVirtual); + bool isPureVirtual = FunctionHelper::isPureVirtualFunction(function, context, + &firstVirtual); + + // Test for regressions introduced by firstVirtual + QCOMPARE(FunctionHelper::isVirtualFunction(function, context), isVirtual); + QCOMPARE(FunctionHelper::isPureVirtualFunction(function, context), isPureVirtual); + if (isVirtual) { + if (isPureVirtual) QCOMPARE(virtuality, PureVirtual); else QCOMPARE(virtuality, Virtual); } else { + QEXPECT_FAIL("virtual-dtor-dtor", "Not implemented", Abort); + if (allFunctions.size() == 3) + QEXPECT_FAIL("dtor-virtual-dtor-dtor", "Not implemented", Abort); QCOMPARE(virtuality, NotVirtual); } + if (firstVirtualIndex == -1) + QVERIFY(!firstVirtual); + else + QCOMPARE(firstVirtual, allFunctions.at(firstVirtualIndex)); } } QVERIFY(virtualityList.isEmpty()); + QVERIFY(firstVirtualList.isEmpty()); } void CppEditorPlugin::test_functionhelper_virtualFunctions_data() @@ -367,55 +407,79 @@ void CppEditorPlugin::test_functionhelper_virtualFunctions_data() typedef QByteArray _; QTest::addColumn<QByteArray>("source"); QTest::addColumn<VirtualityList>("virtualityList"); + QTest::addColumn<QList<int> >("firstVirtualList"); QTest::newRow("none") << _("struct None { void foo() {} };\n") - << (VirtualityList() << NotVirtual); + << (VirtualityList() << NotVirtual) + << (QList<int>() << -1); QTest::newRow("single-virtual") << _("struct V { virtual void foo() {} };\n") - << (VirtualityList() << Virtual); + << (VirtualityList() << Virtual) + << (QList<int>() << 0); QTest::newRow("single-pure-virtual") << _("struct PV { virtual void foo() = 0; };\n") - << (VirtualityList() << PureVirtual); + << (VirtualityList() << PureVirtual) + << (QList<int>() << 0); QTest::newRow("virtual-derived-with-specifier") << _("struct Base { virtual void foo() {} };\n" "struct Derived : Base { virtual void foo() {} };\n") - << (VirtualityList() << Virtual << Virtual); + << (VirtualityList() << Virtual << Virtual) + << (QList<int>() << 0 << 0); QTest::newRow("virtual-derived-implicit") << _("struct Base { virtual void foo() {} };\n" "struct Derived : Base { void foo() {} };\n") - << (VirtualityList() << Virtual << Virtual); + << (VirtualityList() << Virtual << Virtual) + << (QList<int>() << 0 << 0); QTest::newRow("not-virtual-then-virtual") << _("struct Base { void foo() {} };\n" "struct Derived : Base { virtual void foo() {} };\n") - << (VirtualityList() << NotVirtual << Virtual); + << (VirtualityList() << NotVirtual << Virtual) + << (QList<int>() << -1 << 1); QTest::newRow("virtual-final-not-virtual") << _("struct Base { virtual void foo() {} };\n" "struct Derived : Base { void foo() final {} };\n" "struct Derived2 : Derived { void foo() {} };") - << (VirtualityList() << Virtual << Virtual << NotVirtual); + << (VirtualityList() << Virtual << Virtual << NotVirtual) + << (QList<int>() << 0 << 0 << -1); QTest::newRow("virtual-then-pure") << _("struct Base { virtual void foo() {} };\n" "struct Derived : Base { virtual void foo() = 0; };\n" "struct Derived2 : Derived { void foo() {} };") - << (VirtualityList() << Virtual << PureVirtual << Virtual); + << (VirtualityList() << Virtual << PureVirtual << Virtual) + << (QList<int>() << 0 << 0 << 0); QTest::newRow("virtual-virtual-final-not-virtual") << _("struct Base { virtual void foo() {} };\n" "struct Derived : Base { virtual void foo() final {} };\n" "struct Derived2 : Derived { void foo() {} };") - << (VirtualityList() << Virtual << Virtual << NotVirtual); + << (VirtualityList() << Virtual << Virtual << NotVirtual) + << (QList<int>() << 0 << 0 << -1); QTest::newRow("ctor-virtual-dtor") << _("struct Base { Base() {} virtual ~Base() {} };\n") - << (VirtualityList() << NotVirtual << Virtual); + << (VirtualityList() << NotVirtual << Virtual) + << (QList<int>() << -1 << 1); + + QTest::newRow("virtual-dtor-dtor") + << _("struct Base { virtual ~Base() {} };\n" + "struct Derived : Base { ~Derived() {} };\n") + << (VirtualityList() << Virtual << Virtual) + << (QList<int>() << 0 << 0); + + QTest::newRow("dtor-virtual-dtor-dtor") + << _("struct Base { ~Base() {} };\n" + "struct Derived : Base { virtual ~Derived() {} };\n" + "struct Derived2 : Derived { ~Derived2() {} };\n") + << (VirtualityList() << NotVirtual << Virtual << Virtual) + << (QList<int>() << -1 << 1 << 1); } } // namespace Internal diff --git a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h index 3a99fc37f8..933fa3be4e 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h +++ b/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h @@ -74,10 +74,12 @@ class FunctionHelper { public: static bool isVirtualFunction(const CPlusPlus::Function *function, - const CPlusPlus::Snapshot &snapshot); + const CPlusPlus::LookupContext &context, + const CPlusPlus::Function **firstVirtual = 0); static bool isPureVirtualFunction(const CPlusPlus::Function *function, - const CPlusPlus::Snapshot &snapshot); + const CPlusPlus::LookupContext &context, + const CPlusPlus::Function **firstVirtual = 0); static QList<CPlusPlus::Symbol *> overrides(CPlusPlus::Function *function, CPlusPlus::Class *functionsClass, diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 7924113468..5b7bf1655d 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -465,6 +465,8 @@ void TestCase::run() } // anonymous namespace +Q_DECLARE_METATYPE(QList<TestDocumentPtr>) + void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_data() { QTest::addColumn<QByteArray>("header"); @@ -870,6 +872,18 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_data() "}\n" ); + QTest::newRow("skipForwardDeclarationBasic") << _( + "class $Foo {};\n" + "class Foo;\n" + "@Foo foo;\n" + ); + + QTest::newRow("skipForwardDeclarationTemplates") << _( + "template <class E> class $Container {};\n" + "template <class E> class Container;\n" + "@Container<int> container;\n" + ); + QTest::newRow("using_QTCREATORBUG7903_globalNamespace") << _( "namespace NS {\n" "class Foo {};\n" @@ -904,7 +918,6 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_data() " @Foo foo;\n" "}\n" ); - } void CppEditorPlugin::test_FollowSymbolUnderCursor() @@ -914,6 +927,35 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor() test.run(); } +void CppEditorPlugin::test_FollowSymbolUnderCursor_multipleDocuments_data() +{ + QTest::addColumn<QList<TestDocumentPtr> >("documents"); + + QTest::newRow("skipForwardDeclarationBasic") << (QList<TestDocumentPtr>() + << TestDocument::create("class $Foo {};\n", + QLatin1String("defined.h")) + << TestDocument::create("class Foo;\n" + "@Foo foo;\n", + QLatin1String("forwardDeclaredAndUsed.h")) + ); + + QTest::newRow("skipForwardDeclarationTemplates") << (QList<TestDocumentPtr>() + << TestDocument::create("template <class E> class $Container {};\n", + QLatin1String("defined.h")) + << TestDocument::create("template <class E> class Container;\n" + "@Container<int> container;\n", + QLatin1String("forwardDeclaredAndUsed.h")) + ); +} + +void CppEditorPlugin::test_FollowSymbolUnderCursor_multipleDocuments() +{ + QFETCH(QList<TestDocumentPtr>, documents); + + TestCase test(TestCase::FollowSymbolUnderCursorAction, documents); + test.run(); +} + void CppEditorPlugin::test_FollowSymbolUnderCursor_QObject_connect_data() { #define TAG(str) secondQObjectParam ? str : str ", no 2nd QObject" @@ -1314,6 +1356,14 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_data() << (OverrideItemList() << OverrideItem(QLatin1String("Base::virt"), 1) << OverrideItem(QLatin1String("Derived::virt"), 2)); + + QTest::newRow("QTCREATORBUG-10294_cursorIsAtTheEndOfVirtualFunctionName") << _( + "struct Base { virtual void virt() {} };\n" + "struct Derived : Base { void virt() {} };\n" + "void client(Base *b) { b->virt$@(); }\n") + << (OverrideItemList() + << OverrideItem(QLatin1String("Base::virt"), 1) + << OverrideItem(QLatin1String("Derived::virt"), 2)); } void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall() diff --git a/src/plugins/cpptools/abstracteditorsupport.cpp b/src/plugins/cpptools/abstracteditorsupport.cpp index cdbd86f342..ee48c39a33 100644 --- a/src/plugins/cpptools/abstracteditorsupport.cpp +++ b/src/plugins/cpptools/abstracteditorsupport.cpp @@ -38,7 +38,7 @@ namespace CppTools { AbstractEditorSupport::AbstractEditorSupport(CppModelManagerInterface *modelmanager) : - m_modelmanager(modelmanager) + m_modelmanager(modelmanager), m_revision(0) { } @@ -48,6 +48,7 @@ AbstractEditorSupport::~AbstractEditorSupport() void AbstractEditorSupport::updateDocument() { + ++m_revision; m_modelmanager->updateSourceFiles(QStringList(fileName())); } diff --git a/src/plugins/cpptools/abstracteditorsupport.h b/src/plugins/cpptools/abstracteditorsupport.h index e45a50e791..9b5616c690 100644 --- a/src/plugins/cpptools/abstracteditorsupport.h +++ b/src/plugins/cpptools/abstracteditorsupport.h @@ -50,6 +50,7 @@ public: virtual QString fileName() const = 0; void updateDocument(); + unsigned revision() const { return m_revision; } // TODO: find a better place for common utility functions static QString functionAt(const CppModelManagerInterface *mm, @@ -60,6 +61,7 @@ public: private: CppModelManagerInterface *m_modelmanager; + unsigned m_revision; }; } // namespace CppTools diff --git a/src/plugins/cpptools/completionsettingspage.ui b/src/plugins/cpptools/completionsettingspage.ui index e654cf804e..3ff7358375 100644 --- a/src/plugins/cpptools/completionsettingspage.ui +++ b/src/plugins/cpptools/completionsettingspage.ui @@ -107,7 +107,7 @@ <item row="2" column="0"> <widget class="QCheckBox" name="partiallyComplete"> <property name="toolTip"> - <string>Insert the common prefix of available completion items.</string> + <string>Inserts the common prefix of available completion items.</string> </property> <property name="text"> <string>Autocomplete common &prefix</string> @@ -120,7 +120,7 @@ <item row="3" column="0" colspan="2"> <widget class="QCheckBox" name="autoInsertBrackets"> <property name="toolTip"> - <string>Automatically insert semicolons and closing brackets, parentheses, curly braces, and quotes when appropriate.</string> + <string>Automatically inserts semicolons and closing brackets, parentheses, curly braces, and quotes when appropriate.</string> </property> <property name="text"> <string>&Automatically insert matching characters</string> @@ -151,7 +151,7 @@ <item> <widget class="QCheckBox" name="surroundSelectedText"> <property name="toolTip"> - <string>When typing a matching character and there is a text selection, instead of removing the selection, surround it with the corresponding characters.</string> + <string>When typing a matching character and there is a text selection, instead of removing the selection, surrounds it with the corresponding characters.</string> </property> <property name="text"> <string>Surround &text selections</string> @@ -205,7 +205,7 @@ <item> <widget class="QCheckBox" name="enableDoxygenCheckBox"> <property name="toolTip"> - <string>Automatically create a Doxygen comment upon pressing enter after a /**, /*!, //! or ///</string> + <string>Automatically creates a Doxygen comment upon pressing enter after a /**, /*!, //! or ///</string> </property> <property name="text"> <string>Enable Doxygen blocks</string> @@ -233,7 +233,7 @@ <item> <widget class="QCheckBox" name="generateBriefCheckBox"> <property name="toolTip"> - <string>Generate a <i>brief</i> command with an initial description for the corresponding declaration</string> + <string>Generates a <i>brief</i> command with an initial description for the corresponding declaration</string> </property> <property name="text"> <string>Generate brief description</string> @@ -245,7 +245,7 @@ <item> <widget class="QCheckBox" name="leadingAsterisksCheckBox"> <property name="toolTip"> - <string>Add leading asterisks when continuing Qt (/*!) and Java (/**) style comments on new lines</string> + <string>Adds leading asterisks when continuing Qt (/*!) and Java (/**) style comments on new lines</string> </property> <property name="text"> <string>Add leading asterisks</string> diff --git a/src/plugins/cpptools/cppfilesettingspage.cpp b/src/plugins/cpptools/cppfilesettingspage.cpp index 9de31210d8..1571e7ac22 100644 --- a/src/plugins/cpptools/cppfilesettingspage.cpp +++ b/src/plugins/cpptools/cppfilesettingspage.cpp @@ -254,6 +254,7 @@ CppFileSettingsWidget::CppFileSettingsWidget(QWidget *parent) : foreach (const QString &suffix, headerMt.suffixes()) m_ui->headerSuffixComboBox->addItem(suffix); m_ui->licenseTemplatePathChooser->setExpectedKind(Utils::PathChooser::File); + m_ui->licenseTemplatePathChooser->setHistoryCompleter(QLatin1String("Cpp.LicenseTemplate.History")); m_ui->licenseTemplatePathChooser->addButton(tr("Edit..."), this, SLOT(slotEdit())); } diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index 4d5e8a1d9d..7fdb9d0af0 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -64,7 +64,8 @@ namespace CppTools { uint qHash(const ProjectPart &p) { - uint h = qHash(p.defines) ^ p.cVersion ^ p.cxxVersion ^ p.cxxExtensions ^ p.qtVersion; + uint h = qHash(p.toolchainDefines) ^ qHash(p.projectDefines) ^ p.cVersion ^ p.cxxVersion + ^ p.cxxExtensions ^ p.qtVersion; foreach (const QString &i, p.includePaths) h ^= qHash(i); @@ -78,7 +79,9 @@ uint qHash(const ProjectPart &p) bool operator==(const ProjectPart &p1, const ProjectPart &p2) { - if (p1.defines != p2.defines) + if (p1.toolchainDefines != p2.toolchainDefines) + return false; + if (p1.projectDefines != p2.projectDefines) return false; if (p1.cVersion != p2.cVersion) return false; @@ -363,6 +366,22 @@ QStringList CppModelManager::internalFrameworkPaths() const return frameworkPaths; } +static void addUnique(const QList<QByteArray> &defs, QByteArray *macros, QSet<QByteArray> *alreadyIn) +{ + Q_ASSERT(macros); + Q_ASSERT(alreadyIn); + + foreach (const QByteArray &def, defs) { + if (def.trimmed().isEmpty()) + continue; + if (!alreadyIn->contains(def)) { + macros->append(def); + macros->append('\n'); + alreadyIn->insert(def); + } + } +} + QByteArray CppModelManager::internalDefinedMacros() const { QByteArray macros; @@ -372,14 +391,8 @@ QByteArray CppModelManager::internalDefinedMacros() const it.next(); const ProjectInfo pinfo = it.value(); foreach (const ProjectPart::Ptr &part, pinfo.projectParts()) { - const QList<QByteArray> defs = part->defines.split('\n'); - foreach (const QByteArray &def, defs) { - if (!alreadyIn.contains(def)) { - macros += def; - macros.append('\n'); - alreadyIn.insert(def); - } - } + addUnique(part->toolchainDefines.split('\n'), ¯os, &alreadyIn); + addUnique(part->projectDefines.split('\n'), ¯os, &alreadyIn); } } return macros; @@ -422,7 +435,8 @@ void CppModelManager::dumpModelManagerConfiguration() qDebug() << "cxxExtensions:" << cxxExtensions; qDebug() << "Qt version:" << part->qtVersion; qDebug() << "precompiled header:" << part->precompiledHeaders; - qDebug() << "defines:" << part->defines; + qDebug() << "toolchain defines:" << part->toolchainDefines; + qDebug() << "project defines:" << part->projectDefines; qDebug() << "includes:" << part->includePaths; qDebug() << "frameworkPaths:" << part->frameworkPaths; qDebug() << "files:" << part->files; @@ -550,7 +564,7 @@ CppModelManager::WorkingCopy CppModelManager::buildWorkingCopyList() QSetIterator<AbstractEditorSupport *> it(m_extraEditorSupports); while (it.hasNext()) { AbstractEditorSupport *es = it.next(); - workingCopy.insert(es->fileName(), es->contents()); + workingCopy.insert(es->fileName(), es->contents(), es->revision()); } // Add the project configuration file @@ -795,7 +809,7 @@ ProjectPart::Ptr CppModelManager::fallbackProjectPart() const { ProjectPart::Ptr part(new ProjectPart); - part->defines = m_definedMacros; + part->projectDefines = m_definedMacros; part->includePaths = m_includePaths; part->frameworkPaths = m_frameworkPaths; part->cVersion = ProjectPart::C11; diff --git a/src/plugins/cpptools/cppmodelmanager_test.cpp b/src/plugins/cpptools/cppmodelmanager_test.cpp index a7a6aa222e..3325e1832d 100644 --- a/src/plugins/cpptools/cppmodelmanager_test.cpp +++ b/src/plugins/cpptools/cppmodelmanager_test.cpp @@ -217,7 +217,7 @@ void CppToolsPlugin::test_modelmanager_paths_are_clean() ProjectPart::Ptr part(new ProjectPart); part->cxxVersion = ProjectPart::CXX98; part->qtVersion = ProjectPart::Qt5; - part->defines = QByteArray("#define OH_BEHAVE -1\n"); + part->projectDefines = QByteArray("#define OH_BEHAVE -1\n"); part->includePaths = QStringList() << testDataDir.includeDir(false); part->frameworkPaths = QStringList() << testDataDir.frameworksDir(false); pi.appendProjectPart(part); @@ -251,7 +251,7 @@ void CppToolsPlugin::test_modelmanager_framework_headers() ProjectPart::Ptr part(new ProjectPart); part->cxxVersion = ProjectPart::CXX98; part->qtVersion = ProjectPart::Qt5; - part->defines = QByteArray("#define OH_BEHAVE -1\n"); + part->projectDefines = QByteArray("#define OH_BEHAVE -1\n"); part->includePaths << testDataDir.includeDir(); part->frameworkPaths << testDataDir.frameworksDir(); const QString &source = testDataDir.fileFromSourcesDir( @@ -300,7 +300,7 @@ void CppToolsPlugin::test_modelmanager_refresh_also_includes_of_project_files() ProjectPart::Ptr part(new ProjectPart); part->cxxVersion = ProjectPart::CXX98; part->qtVersion = ProjectPart::Qt5; - part->defines = QByteArray("#define OH_BEHAVE -1\n"); + part->projectDefines = QByteArray("#define OH_BEHAVE -1\n"); part->includePaths = QStringList() << testDataDir.includeDir(false); part->files.append(ProjectFile(testCpp, ProjectFile::CXXSource)); pi.appendProjectPart(part); @@ -320,7 +320,7 @@ void CppToolsPlugin::test_modelmanager_refresh_also_includes_of_project_files() QVERIFY(macrosInHeaderBefore.first().name() == "test_modelmanager_refresh_h"); // Introduce a define that will enable another define once the document is reparsed. - part->defines = QByteArray("#define TEST_DEFINE 1\n"); + part->projectDefines = QByteArray("#define TEST_DEFINE 1\n"); pi.clearProjectParts(); pi.appendProjectPart(part); mm->updateProjectInfo(pi); @@ -377,7 +377,7 @@ void CppToolsPlugin::test_modelmanager_refresh_several_times() ProjectPart::Ptr part(new ProjectPart); // Simulate project configuration change by having different defines each time. defines += "\n#define ANOTHER_DEFINE"; - part->defines = defines; + part->projectDefines = defines; part->cxxVersion = ProjectPart::CXX98; part->qtVersion = ProjectPart::Qt5; part->files.append(ProjectFile(testHeader1, ProjectFile::CXXHeader)); @@ -810,7 +810,7 @@ void CppToolsPlugin::test_modelmanager_defines_per_project() part1->files.append(ProjectFile(header, ProjectFile::CXXHeader)); part1->cxxVersion = ProjectPart::CXX11; part1->qtVersion = ProjectPart::NoQt; - part1->defines = QByteArray("#define SUB1\n"); + part1->projectDefines = QByteArray("#define SUB1\n"); part1->includePaths = QStringList() << testDataDirectory.includeDir(false); ProjectPart::Ptr part2(new ProjectPart); @@ -818,7 +818,7 @@ void CppToolsPlugin::test_modelmanager_defines_per_project() part2->files.append(ProjectFile(header, ProjectFile::CXXHeader)); part2->cxxVersion = ProjectPart::CXX11; part2->qtVersion = ProjectPart::NoQt; - part2->defines = QByteArray("#define SUB2\n"); + part2->projectDefines = QByteArray("#define SUB2\n"); part2->includePaths = QStringList() << testDataDirectory.includeDir(false); ProjectInfo pi = mm->projectInfo(project); diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.cpp b/src/plugins/cpptools/cppmodelmanagerinterface.cpp index 31f1b55e18..3992c44bf5 100644 --- a/src/plugins/cpptools/cppmodelmanagerinterface.cpp +++ b/src/plugins/cpptools/cppmodelmanagerinterface.cpp @@ -161,13 +161,7 @@ void ProjectPart::evaluateToolchain(const ToolChain *tc, else includePaths << header.path(); - const QByteArray macros = tc->predefinedMacros(cxxflags); - if (!macros.isEmpty()) { - if (!defines.isEmpty()) - defines += '\n'; - defines += macros; - defines += '\n'; - } + toolchainDefines = tc->predefinedMacros(cxxflags); } static CppModelManagerInterface *g_instance = 0; @@ -235,5 +229,6 @@ void CppModelManagerInterface::ProjectInfo::appendProjectPart(const ProjectPart: // Update defines if (!m_defines.isEmpty()) m_defines.append('\n'); - m_defines.append(part->defines); + m_defines.append(part->toolchainDefines); + m_defines.append(part->projectDefines); } diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.h b/src/plugins/cpptools/cppmodelmanagerinterface.h index e1469efda0..fbb70f7f07 100644 --- a/src/plugins/cpptools/cppmodelmanagerinterface.h +++ b/src/plugins/cpptools/cppmodelmanagerinterface.h @@ -105,7 +105,8 @@ public: QString projectFile; ProjectExplorer::Project *project; QList<ProjectFile> files; - QByteArray defines; + QByteArray projectDefines; + QByteArray toolchainDefines; QStringList includePaths; QStringList frameworkPaths; QStringList precompiledHeaders; diff --git a/src/plugins/cpptools/cppsnapshotupdater.cpp b/src/plugins/cpptools/cppsnapshotupdater.cpp index 0a97a98fdf..fc97875c60 100644 --- a/src/plugins/cpptools/cppsnapshotupdater.cpp +++ b/src/plugins/cpptools/cppsnapshotupdater.cpp @@ -69,7 +69,8 @@ void SnapshotUpdater::update(CppModelManager::WorkingCopy workingCopy) } if (m_projectPart) { - configFile += m_projectPart->defines; + configFile += m_projectPart->toolchainDefines; + configFile += m_projectPart->projectDefines; includePaths = m_projectPart->includePaths; frameworkPaths = m_projectPart->frameworkPaths; if (m_usePrecompiledHeaders) diff --git a/src/plugins/cpptools/cpptoolseditorsupport.cpp b/src/plugins/cpptools/cpptoolseditorsupport.cpp index 85c304cad6..c2a3792c93 100644 --- a/src/plugins/cpptools/cpptoolseditorsupport.cpp +++ b/src/plugins/cpptools/cpptoolseditorsupport.cpp @@ -186,7 +186,7 @@ QByteArray CppEditorSupport::contents() const const int editorRev = editorRevision(); if (m_cachedContentsEditorRevision != editorRev && !m_fileIsBeingReloaded) { m_cachedContentsEditorRevision = editorRev; - m_cachedContents = m_textEditor->textDocument()->contents().toUtf8(); + m_cachedContents = m_textEditor->textDocument()->plainText().toUtf8(); } return m_cachedContents; @@ -392,10 +392,14 @@ void CppEditorSupport::startHighlighting() m_lastHighlightRevision = revision; emit highlighterStarted(&m_highlighter, m_lastHighlightRevision); } else { + const unsigned revision = currentSource(false).revision; + if (m_lastHighlightRevision == revision) + return; + + m_lastHighlightRevision = revision; static const Document::Ptr dummyDoc; static const Snapshot dummySnapshot; m_highlighter = m_highlightingSupport->highlightingFuture(dummyDoc, dummySnapshot); - m_lastHighlightRevision = editorRevision(); emit highlighterStarted(&m_highlighter, m_lastHighlightRevision); } } diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 4643b4aa7e..4c72fdc76f 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -1245,7 +1245,9 @@ bool CvsPlugin::managesDirectory(const QString &directory, QString *topLevel /* * not have a "CVS" directory. The starting directory must be a managed * one. Go up and try to find the first unmanaged parent dir. */ QDir lastDirectory = dir; - for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) { + for (QDir parentDir = lastDirectory; + !parentDir.isRoot() && parentDir.cdUp(); + lastDirectory = parentDir) { if (!checkCVSDirectory(parentDir)) { *topLevel = lastDirectory.absolutePath(); break; diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index e57b0b189e..ec8e6b764a 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -339,7 +339,6 @@ void addCdbOptionPages(QList<Core::IOptionsPage *> *opts) CdbEngine::CdbEngine(const DebuggerStartParameters &sp) : DebuggerEngine(sp), - m_creatorExtPrefix("<qtcreatorcdbext>|"), m_tokenPrefix("<token>"), m_effectiveStartMode(NoStartMode), m_accessible(false), @@ -365,6 +364,8 @@ CdbEngine::CdbEngine(const DebuggerStartParameters &sp) : this, SLOT(operateByInstructionTriggered(bool))); connect(debuggerCore()->action(VerboseLog), SIGNAL(triggered(bool)), this, SLOT(verboseLogTriggered(bool))); + connect(debuggerCore()->action(CreateFullBacktrace), SIGNAL(triggered()), + this, SLOT(createFullBacktrace())); setObjectName(QLatin1String("CdbEngine")); connect(&m_process, SIGNAL(finished(int)), this, SLOT(processFinished())); connect(&m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError())); @@ -597,6 +598,16 @@ void CdbEngine::consoleStubExited() { } +void CdbEngine::createFullBacktrace() +{ + postBuiltinCommand("~*kp", 0, &CdbEngine::handleCreateFullBackTrace); +} + +void CdbEngine::handleCreateFullBackTrace(const CdbEngine::CdbBuiltinCommandPtr &cmd) +{ + debuggerCore()->openTextEditor(QLatin1String("Backtrace $"), QLatin1String(cmd->joinedReply())); +} + void CdbEngine::setupEngine() { if (debug) @@ -1101,6 +1112,7 @@ bool CdbEngine::hasCapability(unsigned cap) const |BreakOnThrowAndCatchCapability // Sort-of: Can break on throw(). |BreakConditionCapability|TracePointCapability |BreakModuleCapability + |CreateFullBacktraceCapability |OperateByInstructionCapability |RunToLineCapability |MemoryAddressCapability); @@ -2541,11 +2553,12 @@ void CdbEngine::parseOutputLine(QByteArray line) while (isCdbPrompt(line)) line.remove(0, CdbPromptLength); // An extension notification (potentially consisting of several chunks) - if (line.startsWith(m_creatorExtPrefix)) { + static const QByteArray creatorExtPrefix = "<qtcreatorcdbext>|"; + if (line.startsWith(creatorExtPrefix)) { // "<qtcreatorcdbext>|type_char|token|remainingChunks|serviceName|message" - const char type = line.at(m_creatorExtPrefix.size()); + const char type = line.at(creatorExtPrefix.size()); // integer token - const int tokenPos = m_creatorExtPrefix.size() + 2; + const int tokenPos = creatorExtPrefix.size() + 2; const int tokenEndPos = line.indexOf('|', tokenPos); QTC_ASSERT(tokenEndPos != -1, return); const int token = line.mid(tokenPos, tokenEndPos - tokenPos).toInt(); diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index 4d8e9d1214..d86c6c50fb 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -156,6 +156,8 @@ private slots: void consoleStubProcessStarted(); void consoleStubExited(); + void createFullBacktrace(); + void handleDoInterruptInferior(const QString &errorMessage); private: @@ -227,6 +229,7 @@ private: void ensureUsing32BitStackInWow64(const CdbBuiltinCommandPtr &cmd); void handleSwitchWow64Stack(const CdbBuiltinCommandPtr &cmd); void jumpToAddress(quint64 address); + void handleCreateFullBackTrace(const CdbBuiltinCommandPtr &cmd); // Extension commands void handleThreads(const CdbExtensionCommandPtr &); @@ -248,7 +251,6 @@ private: unsigned parseStackTrace(const GdbMi &data, bool sourceStepInto); void mergeStartParametersSourcePathMap(); - const QByteArray m_creatorExtPrefix; const QByteArray m_tokenPrefix; QProcess m_process; diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp index b75581e001..3aede9b0e5 100644 --- a/src/plugins/debugger/commonoptionspage.cpp +++ b/src/plugins/debugger/commonoptionspage.cpp @@ -301,7 +301,7 @@ QString CommonOptionsPage::msgSetBreakpointAtFunctionToolTip(const char *functio const QString &hint) { QString result = QLatin1String("<html><head/><body>"); - result += tr("Always add a breakpoint on the <i>%1()</i> function.").arg(QLatin1String(function)); + result += tr("Always adds a breakpoint on the <i>%1()</i> function.").arg(QLatin1String(function)); if (!hint.isEmpty()) { result += QLatin1String("<br>"); result += hint; diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index 7798cf0bfe..c9f794d55d 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -151,7 +151,6 @@ include(cdb/cdb.pri) include(gdb/gdb.pri) include(pdb/pdb.pri) include(lldb/lldb.pri) -include(lldblib/lldbhost.pri) include(qml/qml.pri) include(namedemangler/namedemangler.pri) diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index 709dc128c3..44a36b7588 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -132,16 +132,6 @@ QtcPlugin { } Group { - name: "lldblib" - id: lldblib - prefix: "lldblib/" - files: [ - "ipcenginehost.cpp", "ipcenginehost.h", - "lldbenginehost.cpp", "lldbenginehost.h" - ] - } - - Group { name: "pdb" prefix: "pdb/" files: ["pdbengine.cpp", "pdbengine.h"] @@ -247,16 +237,6 @@ QtcPlugin { ] } - Group { - name: "LLDBOptions" - condition: qbs.targetOS.contains("osx") - files: [ - "lldblib/lldboptionspage.cpp", - "lldblib/lldboptionspage.h", - "lldblib/lldboptionspagewidget.ui", - ] - } - Properties { condition: qbs.targetOS.contains("windows") cpp.dynamicLibraries: [ diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h index 19bc0fe994..4e5a6e4c4f 100644 --- a/src/plugins/debugger/debuggerconstants.h +++ b/src/plugins/debugger/debuggerconstants.h @@ -190,14 +190,12 @@ enum DebuggerEngineType PdbEngineType = 0x008, QmlEngineType = 0x020, QmlCppEngineType = 0x040, - LldbLibEngineType = 0x080, LldbEngineType = 0x100, AllEngineTypes = GdbEngineType | CdbEngineType | PdbEngineType | QmlEngineType | QmlCppEngineType - | LldbLibEngineType | LldbEngineType }; diff --git a/src/plugins/debugger/debuggeritem.h b/src/plugins/debugger/debuggeritem.h index 5802b23f81..c7d9d70777 100644 --- a/src/plugins/debugger/debuggeritem.h +++ b/src/plugins/debugger/debuggeritem.h @@ -42,6 +42,7 @@ namespace Debugger { +class DebuggerItemManager; namespace Internal { class DebuggerItemConfigWidget; class DebuggerItemModel; @@ -63,7 +64,6 @@ public: QString engineTypeName() const; QVariantMap toMap() const; - void reinitializeFromFile(); QVariant id() const { return m_id; } @@ -92,6 +92,7 @@ public: private: DebuggerItem(const QVariant &id); + void reinitializeFromFile(); QVariant m_id; QString m_displayName; @@ -102,6 +103,7 @@ private: friend class Internal::DebuggerItemConfigWidget; friend class Internal::DebuggerItemModel; + friend class DebuggerItemManager; }; } // namespace Debugger diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index cef2fd529a..552018bd98 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -433,10 +433,18 @@ void DebuggerItemManager::setItemData(const QVariant &id, const QString &display for (int i = 0, n = m_debuggers.size(); i != n; ++i) { DebuggerItem &item = m_debuggers[i]; if (item.id() == id) { - item.setDisplayName(displayName); - item.setCommand(fileName); - item.reinitializeFromFile(); - emit m_instance->debuggerUpdated(id); + bool changed = false; + if (item.displayName() != displayName) { + item.setDisplayName(displayName); + changed = true; + } + if (item.command() != fileName) { + item.setCommand(fileName); + item.reinitializeFromFile(); + changed = true; + } + if (changed) + emit m_instance->debuggerUpdated(id); break; } } diff --git a/src/plugins/debugger/debuggeritemmodel.cpp b/src/plugins/debugger/debuggeritemmodel.cpp index f2c2382040..913ebe5e1c 100644 --- a/src/plugins/debugger/debuggeritemmodel.cpp +++ b/src/plugins/debugger/debuggeritemmodel.cpp @@ -37,6 +37,8 @@ namespace Debugger { namespace Internal { +const int AbiRole = Qt::UserRole + 2; + static QList<QStandardItem *> describeItem(const DebuggerItem &item) { QList<QStandardItem *> row; @@ -44,7 +46,7 @@ static QList<QStandardItem *> describeItem(const DebuggerItem &item) row.append(new QStandardItem(item.command().toUserOutput())); row.append(new QStandardItem(item.engineTypeName())); row.at(0)->setData(item.id()); - row.at(0)->setData(item.abiNames(), Qt::UserRole + 2); + row.at(0)->setData(item.abiNames(), AbiRole); row.at(0)->setEditable(false); row.at(1)->setEditable(false); row.at(1)->setData(item.toMap()); @@ -150,15 +152,15 @@ bool DebuggerItemModel::updateDebuggerStandardItem(const DebuggerItem &item, boo QTC_ASSERT(parent, return false); // Do not mark items as changed if they actually are not: - DebuggerItem orig = debuggerItem(sitem); - if (orig == item && DebuggerItemManager::findById(orig.id())) + const DebuggerItem *orig = DebuggerItemManager::findById(item.id()); + if (orig && *orig == item) changed = false; int row = sitem->row(); QFont font = sitem->font(); font.setBold(changed); parent->child(row, 0)->setData(item.displayName(), Qt::DisplayRole); - parent->child(row, 0)->setData(item.abiNames(), Qt::UserRole + 2); + parent->child(row, 0)->setData(item.abiNames(), AbiRole); parent->child(row, 0)->setFont(font); parent->child(row, 1)->setData(item.command().toUserOutput(), Qt::DisplayRole); parent->child(row, 1)->setFont(font); @@ -178,7 +180,7 @@ DebuggerItem DebuggerItemModel::debuggerItem(QStandardItem *sitem) const item.m_id = i->data(); item.setDisplayName(i->data(Qt::DisplayRole).toString()); - QStringList abis = i->data(Qt::UserRole + 2).toStringList(); + QStringList abis = i->data(AbiRole).toStringList(); QList<ProjectExplorer::Abi> abiList; foreach (const QString &abi, abis) abiList << ProjectExplorer::Abi(abi); diff --git a/src/plugins/debugger/debuggerkitconfigwidget.cpp b/src/plugins/debugger/debuggerkitconfigwidget.cpp index 504b260c0f..883d222150 100644 --- a/src/plugins/debugger/debuggerkitconfigwidget.cpp +++ b/src/plugins/debugger/debuggerkitconfigwidget.cpp @@ -174,7 +174,7 @@ void DebuggerKitConfigWidget::onDebuggerRemoved(const QVariant &id) { if (const int pos = indexOf(id)) { m_comboBox->removeItem(pos); - updateComboBox(id); + refresh(); } } diff --git a/src/plugins/debugger/debuggeroptionspage.cpp b/src/plugins/debugger/debuggeroptionspage.cpp index da42957d65..bd0b8d2916 100644 --- a/src/plugins/debugger/debuggeroptionspage.cpp +++ b/src/plugins/debugger/debuggeroptionspage.cpp @@ -39,6 +39,7 @@ #include <utils/qtcassert.h> #include <utils/winutils.h> +#include <QFileInfo> #include <QFormLayout> #include <QHeaderView> #include <QLabel> @@ -59,26 +60,6 @@ static const char debuggingToolsWikiLinkC[] = "http://qt-project.org/wiki/Qt_Cre // DebuggerItemConfigWidget // ----------------------------------------------------------------------- -class DebuggerItemConfigWidget : public QWidget -{ - Q_DECLARE_TR_FUNCTIONS(Debugger::Internal::DebuggerItemConfigWidget) - -public: - explicit DebuggerItemConfigWidget(DebuggerItemModel *model); - DebuggerItem store() const; - void setItem(const DebuggerItem &item); - void apply(); - -private: - QLineEdit *m_displayNameLineEdit; - QLabel *m_cdbLabel; - PathChooser *m_binaryChooser; - QLineEdit *m_abis; - DebuggerItemModel *m_model; - bool m_autodetected; - QVariant m_id; -}; - DebuggerItemConfigWidget::DebuggerItemConfigWidget(DebuggerItemModel *model) : m_model(model) { @@ -90,6 +71,7 @@ DebuggerItemConfigWidget::DebuggerItemConfigWidget(DebuggerItemModel *model) : m_binaryChooser->setExpectedKind(PathChooser::ExistingCommand); m_binaryChooser->setMinimumWidth(400); m_binaryChooser->setHistoryCompleter(QLatin1String("DebuggerPaths")); + connect(m_binaryChooser, SIGNAL(changed(QString)), this, SLOT(commandWasChanged())); m_cdbLabel = new QLabel(this); m_cdbLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); @@ -107,7 +89,7 @@ DebuggerItemConfigWidget::DebuggerItemConfigWidget(DebuggerItemModel *model) : formLayout->addRow(new QLabel(tr("ABIs:")), m_abis); } -DebuggerItem DebuggerItemConfigWidget::store() const +DebuggerItem DebuggerItemConfigWidget::item() const { DebuggerItem item(m_id); if (m_id.isNull()) @@ -116,11 +98,31 @@ DebuggerItem DebuggerItemConfigWidget::store() const item.setDisplayName(m_displayNameLineEdit->text()); item.setCommand(m_binaryChooser->fileName()); item.setAutoDetected(m_autodetected); - item.reinitializeFromFile(); - m_model->updateDebugger(item); + QList<ProjectExplorer::Abi> abiList; + foreach (const QString &a, m_abis->text().split(QRegExp(QLatin1String("[^A-Za-z0-9-_]+")))) { + ProjectExplorer::Abi abi(a); + if (a.isNull()) + continue; + abiList << a; + } + item.setAbis(abiList); + item.setEngineType(m_engineType); return item; } + +void DebuggerItemConfigWidget::store() const +{ + DebuggerItem i = item(); + if (i.isValid()) + m_model->updateDebugger(i); +} + +void DebuggerItemConfigWidget::setAbis(const QStringList &abiNames) +{ + m_abis->setText(abiNames.join(QLatin1String(", "))); +} + void DebuggerItemConfigWidget::setItem(const DebuggerItem &item) { store(); // store away the (changed) settings for future use @@ -157,17 +159,41 @@ void DebuggerItemConfigWidget::setItem(const DebuggerItem &item) m_cdbLabel->setVisible(!text.isEmpty()); m_binaryChooser->setCommandVersionArguments(QStringList(versionCommand)); - m_abis->setText(item.abiNames().join(QLatin1String(", "))); + setAbis(item.abiNames()); + m_engineType = item.engineType(); } void DebuggerItemConfigWidget::apply() { - DebuggerItem item = m_model->currentDebugger(); - if (!item.isValid()) + DebuggerItem current = m_model->currentDebugger(); + if (!current.isValid()) return; // Nothing was selected here. - item = store(); - setItem(item); + store(); + setItem(item()); +} + +void DebuggerItemConfigWidget::commandWasChanged() +{ + // Use DebuggerItemManager as a cache: + const DebuggerItem *existing + = DebuggerItemManager::findByCommand(m_binaryChooser->fileName()); + if (existing) { + setAbis(existing->abiNames()); + m_engineType = existing->engineType(); + } else { + QFileInfo fi = QFileInfo(m_binaryChooser->path()); + if (fi.isExecutable()) { + DebuggerItem tmp = item(); + tmp.reinitializeFromFile(); + setAbis(tmp.abiNames()); + m_engineType = tmp.engineType(); + } else { + setAbis(QStringList()); + m_engineType = NoEngineType; + } + } + m_model->updateDebugger(item()); } // -------------------------------------------------------------------------- diff --git a/src/plugins/debugger/debuggeroptionspage.h b/src/plugins/debugger/debuggeroptionspage.h index fd1782f4b4..29089b4f52 100644 --- a/src/plugins/debugger/debuggeroptionspage.h +++ b/src/plugins/debugger/debuggeroptionspage.h @@ -30,15 +30,23 @@ #ifndef DEBUGGER_DEBUGGEROPTIONSPAGE_H #define DEBUGGER_DEBUGGEROPTIONSPAGE_H +#include "debuggeritem.h" + #include <coreplugin/dialogs/ioptionspage.h> +#include <QWidget> + QT_BEGIN_NAMESPACE +class QLabel; +class QLineEdit; class QPushButton; class QTreeView; -class QWidget; QT_END_NAMESPACE -namespace Utils { class DetailsWidget; } +namespace Utils { +class DetailsWidget; +class PathChooser; +} // namespace Utils namespace Debugger { namespace Internal { @@ -47,6 +55,37 @@ class DebuggerItemModel; class DebuggerItemConfigWidget; class DebuggerKitConfigWidget; +// ----------------------------------------------------------------------- +// DebuggerItemConfigWidget +// ----------------------------------------------------------------------- + +class DebuggerItemConfigWidget : public QWidget +{ + Q_OBJECT + +public: + explicit DebuggerItemConfigWidget(DebuggerItemModel *model); + void setItem(const DebuggerItem &item); + void apply(); + +private slots: + void commandWasChanged(); + +private: + DebuggerItem item() const; + void store() const; + void setAbis(const QStringList &abiNames); + + QLineEdit *m_displayNameLineEdit; + QLabel *m_cdbLabel; + Utils::PathChooser *m_binaryChooser; + QLineEdit *m_abis; + DebuggerItemModel *m_model; + bool m_autodetected; + DebuggerEngineType m_engineType; + QVariant m_id; +}; + // -------------------------------------------------------------------------- // DebuggerOptionsPage // -------------------------------------------------------------------------- diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index a68df5c9c0..f1a02a89d3 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -684,7 +684,7 @@ static bool currentTextEditorPosition(ContextData *data) data->fileName = document->filePath(); if (document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool()) { int lineNumber = textEditor->currentLine(); - QString line = textEditor->textDocument()->contents() + QString line = textEditor->textDocument()->plainText() .section(QLatin1Char('\n'), lineNumber - 1, lineNumber - 1); data->address = DisassemblerLine::addressFromDisassemblyLine(line); } else { @@ -1843,7 +1843,7 @@ void DebuggerPluginPrivate::requestContextMenu(ITextEditor *editor, ITextEditorDocument *document = editor->textDocument(); args.fileName = document->filePath(); if (document->property(Constants::OPENED_WITH_DISASSEMBLY).toBool()) { - QString line = document->contents() + QString line = document->plainText() .section(QLatin1Char('\n'), lineNumber - 1, lineNumber - 1); BreakpointResponse needle; needle.type = BreakpointByAddress; @@ -1956,7 +1956,7 @@ void DebuggerPluginPrivate::toggleBreakpoint() QTC_ASSERT(textEditor, return); const int lineNumber = textEditor->currentLine(); if (textEditor->property(Constants::OPENED_WITH_DISASSEMBLY).toBool()) { - QString line = textEditor->textDocument()->contents() + QString line = textEditor->textDocument()->plainText() .section(QLatin1Char('\n'), lineNumber - 1, lineNumber - 1); quint64 address = DisassemblerLine::addressFromDisassemblyLine(line); toggleBreakpointByAddress(address); @@ -2013,7 +2013,7 @@ void DebuggerPluginPrivate::requestMark(ITextEditor *editor, return; if (editor->property("DisassemblerView").toBool()) { - QString line = editor->textDocument()->contents() + QString line = editor->textDocument()->plainText() .section(QLatin1Char('\n'), lineNumber - 1, lineNumber - 1); quint64 address = DisassemblerLine::addressFromDisassemblyLine(line); toggleBreakpointByAddress(address); diff --git a/src/plugins/debugger/debuggerprotocol.cpp b/src/plugins/debugger/debuggerprotocol.cpp index a65f4f2997..b76bce3489 100644 --- a/src/plugins/debugger/debuggerprotocol.cpp +++ b/src/plugins/debugger/debuggerprotocol.cpp @@ -33,6 +33,9 @@ #include <QDateTime> #include <QDebug> #include <QHostAddress> +#if QT_VERSION >= 0x050200 +#include <QTimeZone> +#endif #include <ctype.h> @@ -503,6 +506,55 @@ static QTime timeFromData(int ms) return ms == -1 ? QTime() : QTime(0, 0, 0, 0).addMSecs(ms); } +#if QT_VERSION >= 0x050200 +// Stolen and adapted from qdatetime.cpp +static void getDateTime(qint64 msecs, int status, QDate *date, QTime *time) +{ + enum { + SECS_PER_DAY = 86400, + MSECS_PER_DAY = 86400000, + SECS_PER_HOUR = 3600, + MSECS_PER_HOUR = 3600000, + SECS_PER_MIN = 60, + MSECS_PER_MIN = 60000, + TIME_T_MAX = 2145916799, // int maximum 2037-12-31T23:59:59 UTC + JULIAN_DAY_FOR_EPOCH = 2440588 // result of julianDayFromDate(1970, 1, 1) + }; + + // Status of date/time + enum StatusFlag { + NullDate = 0x01, + NullTime = 0x02, + ValidDate = 0x04, + ValidTime = 0x08, + ValidDateTime = 0x10, + TimeZoneCached = 0x20, + SetToStandardTime = 0x40, + SetToDaylightTime = 0x80 + }; + + qint64 jd = JULIAN_DAY_FOR_EPOCH; + qint64 ds = 0; + + if (qAbs(msecs) >= MSECS_PER_DAY) { + jd += (msecs / MSECS_PER_DAY); + msecs %= MSECS_PER_DAY; + } + + if (msecs < 0) { + ds = MSECS_PER_DAY - msecs - 1; + jd -= ds / MSECS_PER_DAY; + ds = ds % MSECS_PER_DAY; + ds = MSECS_PER_DAY - ds - 1; + } else { + ds = msecs; + } + + *date = (status & NullDate) ? QDate() : QDate::fromJulianDay(jd); + *time = (status & NullTime) ? QTime() : QTime::fromMSecsSinceStartOfDay(ds); +} +#endif + QString decodeData(const QByteArray &ba, int encoding) { switch (encoding) { @@ -629,15 +681,42 @@ QString decodeData(const QByteArray &ba, int encoding) const QByteArray decodedBa = QByteArray::fromHex(ba); return QString::fromUtf8(decodedBa); } - case MillisecondsSinceEpoch: { - bool ok = false; - const qint64 ms = ba.toLongLong(&ok); - if (!ok) - return QLatin1String(ba); - QDateTime d; - d.setTimeSpec(Qt::UTC); - d.setMSecsSinceEpoch(ms); - return d.isValid() ? d.toString(Qt::TextDate) : QLatin1String("(invalid)"); + case DateTimeInternal: { // 29, DateTimeInternal: msecs, spec, offset, tz, status +#if QT_VERSION >= 0x050200 + int p0 = ba.indexOf('/'); + int p1 = ba.indexOf('/', p0 + 1); + int p2 = ba.indexOf('/', p1 + 1); + int p3 = ba.indexOf('/', p2 + 1); + + qint64 msecs = ba.left(p0).toLongLong(); + ++p0; + Qt::TimeSpec spec = Qt::TimeSpec(ba.mid(p0, p1 - p0).toInt()); + ++p1; + qulonglong offset = ba.mid(p1, p2 - p1).toInt(); + ++p2; + QByteArray timeZoneId = QByteArray::fromHex(ba.mid(p2, p3 - p2)); + ++p3; + int status = ba.mid(p3).toInt(); + + QDate date; + QTime time; + getDateTime(msecs, status, &date, &time); + + QDateTime dateTime; + if (spec == Qt::OffsetFromUTC) { + dateTime = QDateTime(date, time, spec, offset); + } else if (spec == Qt::TimeZone) { + if (!QTimeZone::isTimeZoneIdAvailable(timeZoneId)) + return QLatin1String("<unavailable>"); + dateTime = QDateTime(date, time, QTimeZone(timeZoneId)); + } else { + dateTime = QDateTime(date, time, spec); + } + return dateTime.toString(); +#else + // "Very plain". + return QString::fromLatin1(ba); +#endif } } qDebug() << "ENCODING ERROR: " << encoding; diff --git a/src/plugins/debugger/debuggerprotocol.h b/src/plugins/debugger/debuggerprotocol.h index a71bb6f133..bf90dd226e 100644 --- a/src/plugins/debugger/debuggerprotocol.h +++ b/src/plugins/debugger/debuggerprotocol.h @@ -205,7 +205,7 @@ enum DebuggerEncoding Hex2EncodedFloat8 = 26, IPv6AddressAndHexScopeId = 27, Hex2EncodedUtf8WithoutQuotes = 28, - MillisecondsSinceEpoch = 29 + DateTimeInternal = 29 }; // Keep in sync with dumper.py, symbolgroupvalue.cpp of CDB diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index 59c2158dcf..db2c5b7f5a 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -75,7 +75,6 @@ DebuggerEngine *createGdbEngine(const DebuggerStartParameters &sp); DebuggerEngine *createPdbEngine(const DebuggerStartParameters &sp); DebuggerEngine *createQmlEngine(const DebuggerStartParameters &sp); DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &sp, QString *error); -DebuggerEngine *createLldbLibEngine(const DebuggerStartParameters &sp); DebuggerEngine *createLldbEngine(const DebuggerStartParameters &sp); static const char *engineTypeName(DebuggerEngineType et) @@ -93,8 +92,6 @@ static const char *engineTypeName(DebuggerEngineType et) return "QML engine"; case Debugger::QmlCppEngineType: return "QML C++ engine"; - case Debugger::LldbLibEngineType: - return "LLDB binary engine"; case Debugger::LldbEngineType: return "LLDB command line engine"; case Debugger::AllEngineTypes: @@ -518,8 +515,6 @@ DebuggerEngine *DebuggerRunControlFactory::createEngine(DebuggerEngineType et, return createQmlEngine(sp); case LldbEngineType: return createLldbEngine(sp); - case LldbLibEngineType: - return createLldbLibEngine(sp); case QmlCppEngineType: return createQmlCppEngine(sp, errorMessage); default: diff --git a/src/plugins/debugger/disassembleragent.cpp b/src/plugins/debugger/disassembleragent.cpp index 3dd14440bb..95bda62afd 100644 --- a/src/plugins/debugger/disassembleragent.cpp +++ b/src/plugins/debugger/disassembleragent.cpp @@ -192,7 +192,7 @@ void DisassemblerAgent::resetLocation() if (d->resetLocationScheduled) { d->resetLocationScheduled = false; if (d->locationMark) - d->editor->markableInterface()->removeMark(d->locationMark); + d->editor->textDocument()->markableInterface()->removeMark(d->locationMark); } } @@ -346,14 +346,14 @@ void DisassemblerAgent::updateLocationMarker() int lineNumber = contents.lineForAddress(d->location.address()); if (d->location.needsMarker()) { if (d->locationMark) - d->editor->markableInterface()->removeMark(d->locationMark); + d->editor->textDocument()->markableInterface()->removeMark(d->locationMark); delete d->locationMark; d->locationMark = 0; if (lineNumber) { d->locationMark = new ITextMark(lineNumber); d->locationMark->setIcon(debuggerCore()->locationMarkIcon()); d->locationMark->setPriority(TextEditor::ITextMark::HighPriority); - d->editor->markableInterface()->addMark(d->locationMark); + d->editor->textDocument()->markableInterface()->addMark(d->locationMark); } } @@ -379,7 +379,7 @@ void DisassemblerAgent::updateBreakpointMarkers() const DisassemblerLines contents = d->contentsAtCurrentLocation(); foreach (TextEditor::ITextMark *marker, d->breakpointMarks) - d->editor->markableInterface()->removeMark(marker); + d->editor->textDocument()->markableInterface()->removeMark(marker); qDeleteAll(d->breakpointMarks); d->breakpointMarks.clear(); foreach (BreakpointModelId id, ids) { @@ -393,7 +393,7 @@ void DisassemblerAgent::updateBreakpointMarkers() marker->setIcon(handler->icon(id)); marker->setPriority(ITextMark::NormalPriority); d->breakpointMarks.append(marker); - d->editor->markableInterface()->addMark(marker); + d->editor->textDocument()->markableInterface()->addMark(marker); } } diff --git a/src/plugins/debugger/gdb/gdboptionspage.cpp b/src/plugins/debugger/gdb/gdboptionspage.cpp index a4a336418f..6651f59a65 100644 --- a/src/plugins/debugger/gdb/gdboptionspage.cpp +++ b/src/plugins/debugger/gdb/gdboptionspage.cpp @@ -210,9 +210,9 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent) "You can load additional debugging helpers or modify existing ones here.</p>" "%1</body></html>").arg(howToUsePython)); - textEditCustomDumperCommands = new QTextEdit(groupBoxStartupCommands); + textEditCustomDumperCommands = new QTextEdit(groupBoxCustomDumperCommands); textEditCustomDumperCommands->setAcceptRichText(false); - textEditCustomDumperCommands->setToolTip(groupBoxStartupCommands->toolTip()); + textEditCustomDumperCommands->setToolTip(groupBoxCustomDumperCommands->toolTip()); /* groupBoxPluginDebugging = new QGroupBox(q); @@ -398,7 +398,7 @@ GdbOptionsPageWidget2::GdbOptionsPageWidget2(QWidget *parent) checkBoxAutoEnrichParameters->setText(GdbOptionsPage::tr( "Use common locations for debug information")); checkBoxAutoEnrichParameters->setToolTip(GdbOptionsPage::tr( - "<html><head/><body>Add common paths to locations " + "<html><head/><body>Adds common paths to locations " "of debug information such as <i>/usr/src/debug</i> " "when starting GDB.</body></html>")); @@ -418,7 +418,7 @@ GdbOptionsPageWidget2::GdbOptionsPageWidget2(QWidget *parent) checkBoxEnableReverseDebugging = new QCheckBox(groupBoxDangerous); checkBoxEnableReverseDebugging->setText(GdbOptionsPage::tr("Enable reverse debugging")); checkBoxEnableReverseDebugging->setToolTip(GdbOptionsPage::tr( - "<html><head/><body><p>Enable stepping backwards.</p><p>" + "<html><head/><body><p>Enables stepping backwards.</p><p>" "<b>Note:</b> This feature is very slow and unstable on the GDB side. " "It exhibits unpredictable behavior when going backwards over system " "calls and is very likely to destroy your debugging session.</p></body></html>")); @@ -426,14 +426,14 @@ GdbOptionsPageWidget2::GdbOptionsPageWidget2(QWidget *parent) checkBoxAttemptQuickStart = new QCheckBox(groupBoxDangerous); checkBoxAttemptQuickStart->setText(GdbOptionsPage::tr("Attempt quick start")); checkBoxAttemptQuickStart->setToolTip(GdbOptionsPage::tr( - "<html><head/><body>Postpone reading debug information as long as possible. " + "<html><head/><body>Postpones reading debug information as long as possible. " "This can result in faster startup times at the price of not being able to " "set breakpoints by file and number.</body></html>")); checkBoxMultiInferior = new QCheckBox(groupBoxDangerous); checkBoxMultiInferior->setText(GdbOptionsPage::tr("Debug all children")); checkBoxMultiInferior->setToolTip(GdbOptionsPage::tr( - "<html><head/><body>Keep debugging all children after a fork." + "<html><head/><body>Keeps debugging all children after a fork." "</body></html>")); diff --git a/src/plugins/debugger/lldblib/guest/README b/src/plugins/debugger/lldblib/guest/README deleted file mode 100644 index be9d4fbee7..0000000000 --- a/src/plugins/debugger/lldblib/guest/README +++ /dev/null @@ -1,31 +0,0 @@ -LLDB Guest Engine - -You can use the LLDB debugger from the LLVM project with the Qt Creator debugger -plugin on Mac OS. - -For the Qt Creator build to pick up the LLDB Guest Engine, -you must download the LLDB debugger and configure it -to be included in the Qt Creator build. - -To debug an application, Qt Creator must access the memory of the application. -On Mac OS X, this requires code signing. - -To enable LLDB debugger support in Qt Creator: - -1. To download the LLDB debugger, enter the following command: - svn co http://llvm.org/svn/llvm-project/lldb/trunk lldb - -2. To sign the code, follow the instructions in lldb/docs/code-signing.txt. - -3. To open LLDB in Xcode for building, enter the following command: - open lldb.xcodeproj - then select the Release target and press the build button. - -4. In Xcode, press the build button. - -5. type the following to have the qt creator build system find your lldb build: - export WITH_LLDB=/path/to/lldb - -6. To rebuild Qt Creator, change back to the top level directory of - the Qt Creator source, and enter the following command: - qmake -r && make diff --git a/src/plugins/debugger/lldblib/guest/lldbengineguest.cpp b/src/plugins/debugger/lldblib/guest/lldbengineguest.cpp deleted file mode 100644 index 7a5cd176e1..0000000000 --- a/src/plugins/debugger/lldblib/guest/lldbengineguest.cpp +++ /dev/null @@ -1,761 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#define QT_NO_CAST_FROM_ASCII - -#include "lldbengineguest.h" - -#include "debuggeractions.h" -#include "debuggerconstants.h" -#include "debuggerdialogs.h" -#include "debuggerplugin.h" -#include "debuggerstringutils.h" - -#include "breakhandler.h" -#include "breakpoint.h" -#include "moduleshandler.h" -#include "registerhandler.h" -#include "stackhandler.h" -#include "watchhandler.h" -#include "watchutils.h" -#include "threadshandler.h" - -#include <utils/qtcassert.h> -#include <QDebug> -#include <QProcess> -#include <QFileInfo> -#include <QThread> -#include <QMutexLocker> - -#include <lldb/API/LLDB.h> - -#define DEBUG_FUNC_ENTER \ - showMessage(QString(QLatin1String("LLDB guest engine: %1 ")) \ - .arg(QLatin1String(Q_FUNC_INFO))); \ - qDebug("%s", Q_FUNC_INFO) - -#define SYNC_INFERIOR_OR(x) if (m_running) { x; } - - -namespace Debugger { -namespace Internal { - -void LldbEventListener::listen(lldb::SBListener *listener) -{ - while (true) { - lldb::SBEvent event; - if (listener->WaitForEvent(1000, event)) - emit lldbEvent(&event); - } -} - -LldbEngineGuest::LldbEngineGuest() - : IPCEngineGuest() - , m_running (false) - , m_worker (new LldbEventListener) - , m_lldb (new lldb::SBDebugger) - , m_target (new lldb::SBTarget) - , m_process (new lldb::SBProcess) - , m_listener(new lldb::SBListener("bla")) - , m_relistFrames (false) -#if defined(HAVE_LLDB_PRIVATE) - , py (new PythonLLDBToGdbMiHack) -#endif -{ - qRegisterMetaType<lldb::SBListener *>("lldb::SBListener *"); - qRegisterMetaType<lldb::SBEvent *>("lldb::SBEvent *"); - - m_worker->moveToThread(&m_wThread); - connect(m_worker, SIGNAL(lldbEvent(lldb::SBEvent*)), this, - SLOT(lldbEvent(lldb::SBEvent*)), Qt::BlockingQueuedConnection); - m_wThread.start(); - setObjectName(QLatin1String("LLDBEngineGuest")); -} - -LldbEngineGuest::~LldbEngineGuest() -{ - delete m_lldb; - delete m_target; - delete m_process; - delete m_listener; -} - - -void LldbEngineGuest::nuke() -{ - ::exit(4); -} - -void LldbEngineGuest::setupEngine() -{ - DEBUG_FUNC_ENTER; - - lldb::SBDebugger::Initialize(); - - *m_lldb = lldb::SBDebugger::Create(); - m_lldb->Initialize(); - if (m_lldb->IsValid()) - notifyEngineSetupOk(); - else - notifyEngineSetupFailed(); - -} - -void LldbEngineGuest::setupInferior(const QString &executable, - const QStringList &args, const QStringList &env) -{ - DEBUG_FUNC_ENTER; - - foreach (const QString &s, args) { - m_arguments.append(s.toLocal8Bit()); - } - foreach (const QString &s, env) { - m_environment.append(s.toLocal8Bit()); - } - - qDebug("creating target for %s", executable.toLocal8Bit().data()); - showStatusMessage(QLatin1String("starting ") + executable); - *m_target = m_lldb->CreateTarget(executable.toLocal8Bit().data()); - if (!m_target->IsValid()) { - notifyInferiorSetupFailed(); - return; - } - DEBUG_FUNC_ENTER; - - const char **argp = new const char *[m_arguments.count() + 1]; - argp[m_arguments.count()] = 0; - for (int i = 0; i < m_arguments.count(); i++) { - argp[i] = m_arguments[i].data(); - } - - const char **envp = new const char *[m_environment.count() + 1]; - envp[m_environment.count()] = 0; - for (int i = 0; i < m_environment.count(); i++) { - envp[i] = m_environment[i].data(); - } - lldb::SBError err; - *m_process = m_target->Launch(argp, envp, NULL, NULL, true, err); - - if (!err.Success()) { - showMessage(QString::fromLocal8Bit(err.GetCString())); - qDebug() << err.GetCString(); - notifyInferiorSetupFailed(); - } - - /* - * note, the actual string ptrs are still valid. They are in m_environment. - * They probably leak. Considered the marvelous API, there is not much we can do - */ - delete [] envp; - - if (!m_process->IsValid()) - notifyEngineRunFailed(); - QTC_ASSERT(m_listener->IsValid(), qDebug() << false); - m_listener->StartListeningForEvents(m_process->GetBroadcaster(), UINT32_MAX); - QMetaObject::invokeMethod(m_worker, "listen", Qt::QueuedConnection, - Q_ARG(lldb::SBListener *, m_listener)); - notifyInferiorSetupOk(); -} - -void LldbEngineGuest::runEngine() -{ - DEBUG_FUNC_ENTER; - m_process->Continue(); -} - -void LldbEngineGuest::shutdownInferior() -{ - DEBUG_FUNC_ENTER; - m_process->Kill(); -} - -void LldbEngineGuest::shutdownEngine() -{ - DEBUG_FUNC_ENTER; - m_currentFrame = lldb::SBFrame(); - m_currentThread = lldb::SBThread(); - m_breakpoints.clear(); - m_localesCache.clear(); - - /* - * this leaks. However, Terminate is broken and lldb leaks anyway - * We should kill the engine guest process - */ - - *m_lldb = lldb::SBDebugger(); - // leakd.Terminate(); - notifyEngineShutdownOk(); -} - -void LldbEngineGuest::detachDebugger() -{ - DEBUG_FUNC_ENTER; -} - -void LldbEngineGuest::executeStep() -{ - DEBUG_FUNC_ENTER; - - if (!m_currentThread.IsValid()) - return; - m_currentThread.StepInto(); -} - -void LldbEngineGuest::executeStepOut() -{ - DEBUG_FUNC_ENTER; - - if (!m_currentThread.IsValid()) - return; - m_currentThread.StepOut(); -} - -void LldbEngineGuest::executeNext() -{ - DEBUG_FUNC_ENTER; - - if (!m_currentThread.IsValid()) - return; - m_currentThread.StepOver(); -} - -void LldbEngineGuest::executeStepI() -{ - DEBUG_FUNC_ENTER; - - if (!m_currentThread.IsValid()) - return; - m_currentThread.StepInstruction(false); -} - -void LldbEngineGuest::executeNextI() -{ - DEBUG_FUNC_ENTER; - - if (!m_currentThread.IsValid()) - return; - m_currentThread.StepInstruction(true); -} - -void LldbEngineGuest::continueInferior() -{ - DEBUG_FUNC_ENTER; - - notifyInferiorRunRequested(); - m_process->Continue(); - showStatusMessage(QLatin1String("resuming inferior")); -} -void LldbEngineGuest::interruptInferior() -{ - DEBUG_FUNC_ENTER; - - m_process->Stop(); - notifyInferiorStopOk(); - m_relistFrames = true; - updateThreads(); -} - -void LldbEngineGuest::executeRunToLine(const ContextData &data); -{ - DEBUG_FUNC_ENTER; - - // TODO - Q_UNUSED(data); -} - -void LldbEngineGuest::executeRunToFunction(const QString &functionName) -{ - DEBUG_FUNC_ENTER; - - // TODO - Q_UNUSED(functionName); -} -void LldbEngineGuest::executeJumpToLine(const ContextData &data); -{ - DEBUG_FUNC_ENTER; - - // TODO - Q_UNUSED(data); -} - -void LldbEngineGuest::activateFrame(qint64 token) -{ - DEBUG_FUNC_ENTER; - SYNC_INFERIOR_OR(showMessage(QLatin1String( - "activateFrame called while inferior running")); return); - - currentFrameChanged(token); - m_localesCache.clear(); - - lldb::SBFrame fr = m_currentThread.GetFrameAtIndex(token); - m_currentFrame = fr; - lldb::SBSymbolContext context = fr.GetSymbolContext(lldb::eSymbolContextEverything); - lldb::SBValueList values = fr.GetVariables(true, true, false, true); - QList<WatchData> wd; - QByteArray iname = "local"; - for (uint i = 0; i < values.GetSize(); i++) { - lldb::SBValue v = values.GetValueAtIndex(i); - if (!v.IsInScope(fr)) - continue; - getWatchDataR(v, 1, iname, wd); - } - updateWatchData(true, wd); -} - -void LldbEngineGuest::requestUpdateWatchData(const Internal::WatchData &data, - const Internal::WatchUpdateFlags &) -{ - DEBUG_FUNC_ENTER; - SYNC_INFERIOR_OR(return); - - lldb::SBValue v = m_localesCache.value(QString::fromUtf8(data.iname)); - QList<WatchData> wd; - for (uint j = 0; j < v.GetNumChildren(); j++) { - lldb::SBValue vv = v.GetChildAtIndex(j); - getWatchDataR(vv, 1, data.iname, wd); - } - updateWatchData(false, wd); -} - -void LldbEngineGuest::getWatchDataR(lldb::SBValue v, int level, - const QByteArray &p_iname, QList<WatchData> &wd) -{ - QByteArray iname = p_iname + '.' + QByteArray(v.GetName()); - m_localesCache.insert(QString::fromLocal8Bit(iname), v); - -#if defined(HAVE_LLDB_PRIVATE) - wd += py->expand(p_iname, v, m_currentFrame, *m_process); -#else - WatchData d; - d.name = QString::fromLocal8Bit(v.GetName()); - d.iname = iname; - d.type = QByteArray(v.GetTypeName()).trimmed(); - d.value = (QString::fromLocal8Bit(v.GetValue(m_currentFrame))); - d.hasChildren = v.GetNumChildren(); - d.state = WatchData::State(0); - wd.append(d); -#endif - - if (--level > 0) { - for (uint j = 0; j < v.GetNumChildren(); j++) { - lldb::SBValue vv = v.GetChildAtIndex(j); - getWatchDataR(vv, level, iname, wd); - } - } -} - -void LldbEngineGuest::disassemble(quint64 pc) -{ - DEBUG_FUNC_ENTER; - SYNC_INFERIOR_OR(return); - - if (!m_currentThread.IsValid()) - return; - for (uint j = 0; j < m_currentThread.GetNumFrames(); j++) { - lldb::SBFrame fr = m_currentThread.GetFrameAtIndex(j); - if (pc == fr.GetPCAddress().GetLoadAddress(*m_target)) { - QString linesStr = QString::fromLocal8Bit(fr.Disassemble()); - DisassemblerLines lines; - foreach (const QString &lineStr, linesStr.split(QLatin1Char('\n'))) { - lines.appendLine(DisassemblerLine(lineStr)); - } - disassembled(pc, lines); - } - } -} -void LldbEngineGuest::fetchFrameSource(qint64 frame) -{ - QFile f(m_frame_to_file.value(frame)); - f.open(QFile::ReadOnly); - frameSourceFetched(frame, QFileInfo(m_frame_to_file.value(frame)).fileName() - , QString::fromLocal8Bit(f.readAll())); -} - -void LldbEngineGuest::addBreakpoint(BreakpointId id, - const Internal::BreakpointParameters &bp_) -{ - DEBUG_FUNC_ENTER; - SYNC_INFERIOR_OR(notifyAddBreakpointFailed(id); return); - - Internal::BreakpointParameters bp(bp_); - - lldb::SBBreakpoint llbp = m_target->BreakpointCreateByLocation( - bp.fileName.toLocal8Bit().constData(), bp.lineNumber); - if (llbp.IsValid()) { - m_breakpoints.insert(id, llbp); - - llbp.SetIgnoreCount(bp.ignoreCount); - bp.ignoreCount = llbp.GetIgnoreCount(); - bp.enabled = llbp.IsEnabled(); - - lldb::SBBreakpointLocation location = llbp.GetLocationAtIndex(0); - if (location.IsValid()) { - bp.address = location.GetLoadAddress(); - - // FIXME get those from lldb - bp.lineNumber = bp.lineNumber; - bp.fileName = bp.fileName; - notifyAddBreakpointOk(id); - showMessage(QLatin1String("[BB] ok.")); - notifyBreakpointAdjusted(id, bp); - } else { - m_breakpoints.take(id); - showMessage(QLatin1String("[BB] failed. cant resolve yet")); -// notifyAddBreakpointFailed(id); -// notifyAddBreakpointOk(id); - } - } else { - showMessage(QLatin1String("[BB] failed. dunno.")); - notifyAddBreakpointFailed(id); - } -} - -void LldbEngineGuest::removeBreakpoint(BreakpointId id) -{ - DEBUG_FUNC_ENTER; - SYNC_INFERIOR_OR(notifyRemoveBreakpointFailed(id); return); - - lldb::SBBreakpoint llbp = m_breakpoints.take(id); - llbp.SetEnabled(false); - notifyRemoveBreakpointOk(id); -} - -void LldbEngineGuest::changeBreakpoint(BreakpointId id, - const Internal::BreakpointParameters &bp) -{ - DEBUG_FUNC_ENTER; - - // TODO - Q_UNUSED(id); - Q_UNUSED(bp); -} - -void LldbEngineGuest::selectThread(qint64 token) -{ - DEBUG_FUNC_ENTER; - SYNC_INFERIOR_OR(return); - - m_frame_to_file.clear(); - for (uint i = 0; i < m_process->GetNumThreads(); i++) { - lldb::SBThread t = m_process->GetThreadAtIndex(i); - if (t.GetThreadID() == token) { - m_currentThread = t; - StackFrames frames; - int firstResolvableFrame = -1; - for (uint j = 0; j < t.GetNumFrames(); j++) { - lldb::SBFrame fr = t.GetFrameAtIndex(j); - if (!fr.IsValid()) { - qDebug("warning: frame %i is garbage", j); - continue; - } - lldb::SBSymbolContext context = - fr.GetSymbolContext(lldb::eSymbolContextEverything); - lldb::SBSymbol sym = fr.GetSymbol(); - lldb::SBFunction func = fr.GetFunction(); - lldb::SBCompileUnit tu = fr.GetCompileUnit(); - lldb::SBModule module = fr.GetModule(); - lldb::SBBlock block = fr.GetBlock(); - lldb::SBBlock fblock = fr.GetFrameBlock(); - lldb::SBLineEntry le = fr.GetLineEntry(); - lldb::SBValueList values = fr.GetVariables(true, true, true, false); -#if 0 - qDebug()<<"\tframe "<<fr.GetFrameID(); - qDebug() << "\t\tPC: " << ("0x" + QByteArray::number( - fr.GetPCAddress().GetLoadAddress(*m_target), 16)).data(); - qDebug() << "\t\tFP: " << ("0x" + QByteArray::number(fr.GetFP(), 16)).data(); - qDebug() << "\t\tSP: " << ("0x" + QByteArray::number(fr.GetSP(), 16)).data(); - qDebug() << "\t\tsymbol: " << sym.IsValid() << sym.GetName() << sym.GetMangledName(); - qDebug() << "\t\tfunction:" << func.IsValid(); - qDebug() << "\t\ttu: " << tu.IsValid(); - if (tu.IsValid()) - - qDebug() << "\t\tmodule: " << module.IsValid() << module.GetFileSpec().IsValid() - << module.GetFileSpec().GetFilename(); - qDebug() << "\t\tblock: " << block.IsValid() << block.GetInlinedName(); - qDebug() << "\t\tfblock: " << block.IsValid() << block.GetInlinedName(); - qDebug() << "\t\tle: " << le.IsValid() << le.GetLine()<<le.GetColumn(); - qDebug() << "\t\tvalues: "<<values.IsValid() << values.GetSize(); - qDebug() << "\t\tcontext: " << context.IsValid(); - qDebug() << "\t\t\tmodule: " << context.GetModule().IsValid(); - qDebug() << "\t\t\tfunction: " << context.GetFunction().IsValid(); - qDebug() << "\t\t\tblock: " << context.GetBlock().IsValid(); - qDebug() << "\t\t\tle: " << context.GetLineEntry().IsValid(); - qDebug() << "\t\t\tsymbol: " << context.GetSymbol().IsValid(); -// qDebug() << "\t\tdisassemly -->\n" << fr.Disassemble() << "<--"; -#endif - - QString sourceFile; - QString sourceFilePath; - int lineNumber = 0; - if (le.IsValid()) { - lineNumber = le.GetLine(); - if (le.GetFileSpec().IsValid()) { - sourceFile = QString::fromLocal8Bit(le.GetFileSpec().GetFilename()); - sourceFilePath = QString::fromLocal8Bit(le.GetFileSpec().GetDirectory()) - + QLatin1String("/") + sourceFile; - if (firstResolvableFrame < 0) - firstResolvableFrame = j; - } - } - sourceFilePath = QFileInfo(sourceFilePath).canonicalFilePath(); - - QString functionName; - if (func.IsValid()) - functionName = QString::fromLocal8Bit(func.GetName()); - else - functionName = QString::fromLocal8Bit(sym.GetName()); - - StackFrame frame; - frame.level = fr.GetFrameID(); - if (func.IsValid()) - frame.function = QString::fromLocal8Bit(func.GetName()); - else - frame.function = QString::fromLocal8Bit(sym.GetName()); - frame.from = QString::fromLocal8Bit(module.GetFileSpec().GetFilename()); - frame.address = fr.GetPCAddress().GetLoadAddress(*m_target); - frame.line = lineNumber; - frame.file = sourceFilePath; - frame.usable = QFileInfo(frame.file).isReadable(); - frames.append(frame); - m_frame_to_file.insert(j, frame.file); - } - currentThreadChanged(token); - listFrames(frames); - activateFrame(firstResolvableFrame > -1 ? firstResolvableFrame : 0); - return; - } - } -} - -void LldbEngineGuest::updateThreads() -{ - DEBUG_FUNC_ENTER; - SYNC_INFERIOR_OR(return); - - /* There is no way to find the StopReason of a _process_ - * We try to emulate gdb here, by assuming there must be exactly one 'guilty' thread. - * However, if there are no threads at all, it must be that the process - * no longer exists. Let's tear down the whole session. - */ - if (m_process->GetNumThreads() < 1) { - notifyEngineSpontaneousShutdown(); - m_process->Kill(); - m_process->Destroy(); - } - - Threads threads; - for (uint i = 0; i < m_process->GetNumThreads(); i++) { - lldb::SBThread t = m_process->GetThreadAtIndex(i); - if (!t.IsValid()) { - qDebug("warning: thread %i is garbage", i); - continue; - } - ThreadData thread; - thread.id = t.GetThreadID(); - thread.targetId = QString::number(t.GetThreadID()); - thread.core.clear(); - thread.state = QString::number(t.GetStopReason()); - - switch (t.GetStopReason()) { - case lldb::eStopReasonInvalid: - case lldb::eStopReasonNone: - case lldb::eStopReasonTrace: - thread.state = QLatin1String("running"); - break; - case lldb::eStopReasonBreakpoint: - case lldb::eStopReasonWatchpoint: - showStatusMessage(QLatin1String("hit breakpoint")); - thread.state = QLatin1String("hit breakpoint"); - if (m_currentThread.GetThreadID() != t.GetThreadID()) { - m_currentThread = t; - currentThreadChanged(t.GetThreadID()); - m_relistFrames = true; - } - break; - case lldb::eStopReasonSignal: - showStatusMessage(QLatin1String("stopped")); - thread.state = QLatin1String("stopped"); - if (m_currentThread.GetThreadID() != t.GetThreadID()) { - m_currentThread = t; - currentThreadChanged(t.GetThreadID()); - m_relistFrames = true; - } - break; - case lldb::eStopReasonException: - showStatusMessage(QLatin1String("application crashed.")); - thread.state = QLatin1String("crashed"); - if (m_currentThread.GetThreadID() != t.GetThreadID()) { - m_currentThread = t; - currentThreadChanged(t.GetThreadID()); - m_relistFrames = true; - } - break; - case lldb::eStopReasonPlanComplete: - thread.state = QLatin1String("crazy things happened"); - break; - }; - - thread.lineNumber = 0; - thread.name = QString::fromLocal8Bit(t.GetName()); - - lldb::SBFrame fr = t.GetFrameAtIndex(0); - if (!fr.IsValid()) { - qDebug("warning: frame 0 is garbage"); - continue; - } - lldb::SBSymbolContext context = fr.GetSymbolContext(lldb::eSymbolContextEverything); - lldb::SBSymbol sym = fr.GetSymbol(); - lldb::SBFunction func = fr.GetFunction(); - lldb::SBLineEntry le = fr.GetLineEntry(); - QString sourceFile; - QString sourceFilePath; - int lineNumber = 0; - if (le.IsValid()) { - lineNumber = le.GetLine(); - if (le.GetFileSpec().IsValid()) { - sourceFile = QString::fromLocal8Bit(le.GetFileSpec().GetFilename()); - sourceFilePath = QString::fromLocal8Bit(le.GetFileSpec().GetDirectory()) - + QLatin1String("/") + sourceFile; - } - } - QString functionName; - if (func.IsValid()) - functionName = QString::fromLocal8Bit(func.GetName()); - else - functionName = QString::fromLocal8Bit(sym.GetName()); - - lldb::SBValueList values = fr.GetVariables(true, true, false, false); - thread.fileName = sourceFile; - thread.function = functionName; - thread.address = fr.GetPCAddress().GetLoadAddress(*m_target); - thread.lineNumber = lineNumber; - threads.append(thread); - } - listThreads(threads); - if (m_relistFrames) { - selectThread(m_currentThread.GetThreadID()); - m_relistFrames = false; - } -} - -void LldbEngineGuest::lldbEvent(lldb::SBEvent *ev) -{ - qDebug() << "lldbevent" << ev->GetType() << - m_process->GetState() << (int)state(); - - uint32_t etype = ev->GetType(); - switch (etype) { - // ProcessEvent - case 1: - switch (m_process->GetState()) { - case lldb::eStateRunning: // 5 - if (!m_running) - m_running = true; - notifyInferiorPid(m_process->GetProcessID()); - switch (state()) { - case EngineRunRequested: - notifyEngineRunAndInferiorRunOk(); - break; - case InferiorRunRequested: - notifyInferiorRunOk(); - break; - case InferiorStopOk: - notifyInferiorRunRequested(); - notifyInferiorRunOk(); - break; - default: - break; - } - break; - case lldb::eStateExited: // 9 - if (m_running) - m_running = false; - switch (state()) { - case InferiorShutdownRequested: - notifyInferiorShutdownOk(); - break; - case InferiorRunOk: - m_relistFrames = true; - updateThreads(); - notifyEngineSpontaneousShutdown(); - m_process->Kill(); - m_process->Destroy(); - break; - default: - updateThreads(); - break; - } - break; - case lldb::eStateStopped: // 4 - if (m_running) - m_running = false; - switch (state()) { - case InferiorShutdownRequested: - notifyInferiorShutdownOk(); - break; - case InferiorRunOk: - m_relistFrames = true; - updateThreads(); - notifyInferiorSpontaneousStop(); - // fall - default: - m_relistFrames = true; - updateThreads(); - break; - } - break; - case lldb::eStateCrashed: // 7 - if (m_running) - m_running = false; - switch (state()) { - case InferiorShutdownRequested: - notifyInferiorShutdownOk(); - break; - case InferiorRunOk: - m_relistFrames = true; - updateThreads(); - notifyInferiorSpontaneousStop(); - break; - default: - break; - } - break; - default: - qDebug("unexpected ProcessEvent"); - break; - } - break; - default: - break; - }; -} - - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/lldblib/guest/lldbengineguest.h b/src/plugins/debugger/lldblib/guest/lldbengineguest.h deleted file mode 100644 index c11ac3f0a3..0000000000 --- a/src/plugins/debugger/lldblib/guest/lldbengineguest.h +++ /dev/null @@ -1,136 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#ifndef DEBUGGER_LLDBENGINE_GUEST_H -#define DEBUGGER_LLDBENGINE_GUEST_H - -#include "ipcengineguest.h" - -#include <QQueue> -#include <QVariant> -#include <QThread> -#include <QStringList> - -#include <lldb/API/LLDB.h> - -#if defined(HAVE_LLDB_PRIVATE) -#include "pygdbmiemu.h" -#endif - -Q_DECLARE_METATYPE (lldb::SBListener *) -Q_DECLARE_METATYPE (lldb::SBEvent *) - -namespace Debugger { -namespace Internal { - -class LldbEventListener : public QObject -{ -Q_OBJECT -public slots: - void listen(lldb::SBListener *listener); -signals: - // lldb API uses non thread safe implicit sharing with no explicit copy feature - // additionally the scope is undefined, hence this signal needs to be connected BlockingQueued - // whutever, works for now. - void lldbEvent(lldb::SBEvent *ev); -}; - - -class LldbEngineGuest : public IPCEngineGuest -{ - Q_OBJECT - -public: - explicit LldbEngineGuest(); - ~LldbEngineGuest(); - - void nuke(); - void setupEngine(); - void setupInferior(const QString &executable, const QStringList &arguments, - const QStringList &environment); - void runEngine(); - void shutdownInferior(); - void shutdownEngine(); - void detachDebugger(); - void executeStep(); - void executeStepOut() ; - void executeNext(); - void executeStepI(); - void executeNextI(); - void continueInferior(); - void interruptInferior(); - void executeRunToLine(const ContextData &data); - void executeRunToFunction(const QString &functionName); - void executeJumpToLine(const ContextData &data); - void activateFrame(qint64); - void selectThread(qint64); - void disassemble(quint64 pc); - void addBreakpoint(BreakpointModelId id, const BreakpointParameters &bp); - void removeBreakpoint(BreakpointModelId id); - void changeBreakpoint(BreakpointModelId id, const BreakpointParameters &bp); - void requestUpdateWatchData(const WatchData &data, - const WatchUpdateFlags &flags); - void fetchFrameSource(qint64 frame); - -private: - bool m_running; - - QList<QByteArray> m_arguments; - QList<QByteArray> m_environment; - QThread m_wThread; - LldbEventListener *m_worker; - lldb::SBDebugger *m_lldb; - lldb::SBTarget *m_target; - lldb::SBProcess *m_process; - lldb::SBListener *m_listener; - - lldb::SBFrame m_currentFrame; - lldb::SBThread m_currentThread; - bool m_relistFrames; - QHash<QString, lldb::SBValue> m_localesCache; - QHash<BreakpointModelId, lldb::SBBreakpoint> m_breakpoints; - QHash<qint64, QString> m_frame_to_file; - - void updateThreads(); - void getWatchDataR(lldb::SBValue v, int level, - const QByteArray &p_iname, QList<WatchData> &wd); - -#if defined(HAVE_LLDB_PRIVATE) - PythonLLDBToGdbMiHack * py; -#endif - -private slots: - void lldbEvent(lldb::SBEvent *ev); -}; - -} // namespace Internal -} // namespace Debugger - -#endif // DEBUGGER_LLDBENGINE_H -#define SYNC_INFERIOR diff --git a/src/plugins/debugger/lldblib/guest/main.cpp b/src/plugins/debugger/lldblib/guest/main.cpp deleted file mode 100644 index 9803a490f8..0000000000 --- a/src/plugins/debugger/lldblib/guest/main.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "lldbengineguest.h" - -#include <QLocalSocket> -#include <QCoreApplication> -#include <QSocketNotifier> -#include <QQueue> - -#include <cstdio> - -// #define DO_STDIO_DEBUG 1 -#ifdef DO_STDIO_DEBUG -#define D_STDIO0(x) qDebug(x) -#define D_STDIO1(x,a1) qDebug(x,a1) -#define D_STDIO2(x,a1,a2) qDebug(x,a1,a2) -#define D_STDIO3(x,a1,a2,a3) qDebug(x,a1,a2,a3) -#else -#define D_STDIO0(x) -#define D_STDIO1(x,a1) -#define D_STDIO2(x,a1,a2) -#define D_STDIO3(x,a1,a2,a3) -#endif - -class Stdio : public QIODevice -{ - Q_OBJECT -public: - QSocketNotifier notify; - Stdio() - : QIODevice() - , notify(fileno(stdin), QSocketNotifier::Read) - , buckethead(0) - { - setvbuf(stdin , NULL , _IONBF , 0); - setvbuf(stdout , NULL , _IONBF , 0); - setOpenMode(QIODevice::ReadWrite | QIODevice::Unbuffered); - connect(¬ify, SIGNAL(activated(int)), this, SLOT(activated())); - } - virtual qint64 bytesAvailable () const - { - qint64 r = QIODevice::bytesAvailable(); - foreach (const QByteArray &bucket, buckets) - r += bucket.size(); - r-= buckethead; - return r; - } - - virtual qint64 readData (char * data, qint64 maxSize) - { - D_STDIO1("readData %lli",maxSize); - qint64 size = maxSize; - while (size > 0) { - if (!buckets.size()) { - D_STDIO1("done prematurely with %lli", maxSize - size); - return maxSize - size; - } - QByteArray &bucket = buckets.head(); - if ((size + buckethead) >= bucket.size()) { - int d = bucket.size() - buckethead; - D_STDIO3("read (over bucket) d: %i buckethead: %i bucket.size(): %i", - d, buckethead, bucket.size()); - memcpy(data, bucket.data() + buckethead, d); - data += d; - size -= d; - buckets.dequeue(); - buckethead = 0; - } else { - D_STDIO1("read (in bucket) size: %lli", size); - memcpy(data, bucket.data() + buckethead, size); - data += size; - buckethead += size; - size = 0; - } - } - D_STDIO1("done with %lli",(maxSize - size)); - return maxSize - size; - } - - virtual qint64 writeData (const char * data, qint64 maxSize) - { - return ::write(fileno(stdout), data, maxSize); - } - - QQueue<QByteArray> buckets; - int buckethead; - -private slots: - void activated() - { - QByteArray a; - a.resize(1000); - int ret = ::read(fileno(stdin), a.data(), 1000); - if (ret == 0) - ::exit(0); - assert(ret <= 1000); - D_STDIO1("activated %i", ret); - a.resize(ret); - buckets.enqueue(a); - emit readyRead(); - } -}; - -int main(int argc, char **argv) -{ - QCoreApplication app(argc, argv); - qDebug() << "guest engine operational"; - - Debugger::Internal::LldbEngineGuest lldb; - - - Stdio stdio; - lldb.setHostDevice(&stdio); - - return app.exec(); -} - -extern "C" { -extern const unsigned char lldbVersionString[] __attribute__ ((used)) = "@(#)PROGRAM:lldb PROJECT:lldb-26" "\n"; -extern const double lldbVersionNumber __attribute__ ((used)) = (double)26.; -extern const double LLDBVersionNumber __attribute__ ((used)) = (double)26.; -} - -#include "main.moc" diff --git a/src/plugins/debugger/lldblib/guest/qtcreator-lldb.plist b/src/plugins/debugger/lldblib/guest/qtcreator-lldb.plist deleted file mode 100644 index c0a3b2beaf..0000000000 --- a/src/plugins/debugger/lldblib/guest/qtcreator-lldb.plist +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>CFBundleDevelopmentRegion</key> - <string>English</string> - <key>CFBundleIdentifier</key> - <string>org.qt-project.qtcreator-lldb</string> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> - <key>CFBundleName</key> - <string>Qt Creator LLDB Guest</string> - <key>CFBundleVersion</key> - <string>1.0</string> - <key>SecTaskAccess</key> - <array> - <string>allowed</string> - <string>safe</string> - </array> -</dict> -</plist> diff --git a/src/plugins/debugger/lldblib/guest/qtcreator-lldb.pri b/src/plugins/debugger/lldblib/guest/qtcreator-lldb.pri deleted file mode 100644 index f44c3e9c84..0000000000 --- a/src/plugins/debugger/lldblib/guest/qtcreator-lldb.pri +++ /dev/null @@ -1,2 +0,0 @@ -WITH_LLDB = $$(WITH_LLDB) -macx: !isEmpty(WITH_LLDB) : SUBDIRS += $$PWD/qtcreator-lldb.pro diff --git a/src/plugins/debugger/lldblib/guest/qtcreator-lldb.pro b/src/plugins/debugger/lldblib/guest/qtcreator-lldb.pro deleted file mode 100644 index b6f5437284..0000000000 --- a/src/plugins/debugger/lldblib/guest/qtcreator-lldb.pro +++ /dev/null @@ -1,61 +0,0 @@ -WITH_LLDB = $$(WITH_LLDB) - -!macx: error (This can only be built on mac) -!exists($${WITH_LLDB}/include/lldb/lldb-enumerations.h): error(please see the README for build instructions) - -QT = core network - -include(../../../../../qtcreator.pri) -TEMPLATE = app -CONFIG -= app_bundle -CONFIG += debug -TARGET = qtcreator-lldb -DEPENDPATH += . .. ../.. ../../.. -INCLUDEPATH += . .. ../.. ../../.. -DESTDIR = $$IDE_LIBEXEC_PATH - -MOC_DIR=.tmp -OBJECTS_DIR=.tmp - -HEADERS += ../ipcengineguest.h \ - ../debuggerstreamops.h \ - ../breakpoint.h \ - ../watchdata.h \ - ../stackframe.h \ - ../disassemblerlines.h \ - lldbengineguest.h - -SOURCES += ../ipcengineguest.cpp \ - ../debuggerstreamops.cpp \ - ../breakpoint.cpp \ - ../watchdata.cpp \ - ../stackframe.cpp \ - ../disassemblerlines.cpp \ - lldbengineguest.cpp \ - main.cpp - - -LIBS += -sectcreate __TEXT __info_plist $$PWD/qtcreator-lldb.plist - -POSTL = rm -rf \'$${IDE_LIBEXEC_PATH}/LLDB.framework\' $$escape_expand(\\n\\t) \ - $$QMAKE_COPY_DIR $${WITH_LLDB}/build/Release/* \'$$IDE_LIBEXEC_PATH\' $$escape_expand(\\n\\t) \ - install_name_tool -change '@rpath/LLDB.framework/Versions/A/LLDB' '@executable_path/LLDB.framework/Versions/A/LLDB' $(TARGET) $$escape_expand(\\n\\t) \ - codesign -s lldb_codesign $(TARGET) - -!isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$escape_expand(\\n\\t)$$QMAKE_POST_LINK -QMAKE_POST_LINK = $$POSTL $$QMAKE_POST_LINK -silent:QMAKE_POST_LINK = @echo signing $@ && $$QMAKE_POST_LINK - -LIBS += -framework Security -framework Python - -DEFINES += __STDC_LIMIT_MACROS __STDC_CONSTANT_MACROS - -INCLUDEPATH += $${WITH_LLDB}/include $${WITH_LLDB}/llvm/include/ -LIBS += -F$${WITH_LLDB}/build/Release -framework LLDB - -# include (lldb.pri) -# DEFINES += HAVE_LLDB_PRIVATE -# HEADERS += pygdbmiemu.h -# SOURCES += pygdbmiemu.cpp - - diff --git a/src/plugins/debugger/lldblib/ipcengineguest.cpp b/src/plugins/debugger/lldblib/ipcengineguest.cpp deleted file mode 100644 index 50ebae4177..0000000000 --- a/src/plugins/debugger/lldblib/ipcengineguest.cpp +++ /dev/null @@ -1,637 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "ipcengineguest.h" -#include "ipcenginehost.h" -#include "breakpoint.h" -#include "stackframe.h" -#include "threaddata.h" -#include "debuggerstreamops.h" - -#include <utils/qtcassert.h> - -#include <QLocalSocket> - -#include <QSysInfo> -#include <QDebug> -#include <QFileInfo> -#include <QTimer> - -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -#define SET_NATIVE_BYTE_ORDER(x) x.setByteOrder(QDataStream::LittleEndian) -#else -#define SET_NATIVE_BYTE_ORDER(x) x.setByteOrder(QDataStream::BigEndian) -#endif - -namespace Debugger { -namespace Internal { - -IPCEngineGuest::IPCEngineGuest() - : QObject() - , m_local_host(0) - , m_nextMessagePayloadSize(0) - , m_cookie(1) - , m_device(0) -{ -} - -IPCEngineGuest::~IPCEngineGuest() -{ -} - -void IPCEngineGuest::setLocalHost(IPCEngineHost *host) -{ - m_local_host = host; -} - -void IPCEngineGuest::setHostDevice(QIODevice *device) -{ - if (m_device) { - disconnect(m_device, SIGNAL(readyRead()), this, SLOT(readyRead())); - delete m_device; - } - m_device = device; - if (m_device) - connect(m_device, SIGNAL(readyRead()), SLOT(readyRead())); -} - -void IPCEngineGuest::rpcCall(Function f, QByteArray payload) -{ -#if 0 - if (m_local_host) { - QMetaObject::invokeMethod(m_local_host, - "rpcCallback", - Qt::QueuedConnection, - Q_ARG(quint64, f), - Q_ARG(QByteArray, payload)); - } else -#endif - if (m_device) { - { - QDataStream s(m_device); - SET_NATIVE_BYTE_ORDER(s); - s << m_cookie++; - s << quint64(f); - s << quint64(payload.size()); - } - m_device->write(payload); - m_device->putChar('T'); - QLocalSocket *sock = qobject_cast<QLocalSocket *>(m_device); - if (sock) - sock->flush(); - } -} - -void IPCEngineGuest::readyRead() -{ - if (!m_nextMessagePayloadSize) { - if (quint64(m_device->bytesAvailable()) < 3 * sizeof(quint64)) - return; - QDataStream s(m_device); - SET_NATIVE_BYTE_ORDER(s); - s >> m_nextMessageCookie; - s >> m_nextMessageFunction; - s >> m_nextMessagePayloadSize; - m_nextMessagePayloadSize += 1; // terminator and "got header" marker - } - - quint64 ba = m_device->bytesAvailable(); - if (ba < m_nextMessagePayloadSize) - return; - - qint64 rrr = m_nextMessagePayloadSize; - QByteArray payload = m_device->read(rrr); - if (quint64(payload.size()) != m_nextMessagePayloadSize || !payload.endsWith('T')) { - qDebug("IPC Error: corrupted frame"); - showMessage(QLatin1String("[guest] IPC Error: corrupted frame"), LogError); - nuke(); - return; - } - payload.chop(1); - rpcCallback(m_nextMessageFunction, payload); - m_nextMessagePayloadSize = 0; - - if (quint64(m_device->bytesAvailable ()) >= 3 * sizeof(quint64)) - QTimer::singleShot(0, this, SLOT(readyRead())); -} - -void IPCEngineGuest::rpcCallback(quint64 f, QByteArray payload) -{ - switch (f) { - default: - qDebug("IPC Error: unhandled id in host to guest call"); - showMessage(QLatin1String("IPC Error: unhandled id in host to guest call"), LogError); - nuke(); - break; - case IPCEngineHost::SetupIPC: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - int version; - s >> version; - Q_ASSERT(version == 1); - } - break; - case IPCEngineHost::StateChanged: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 st; - s >> st; - m_state = (DebuggerState)st; - } - break; - case IPCEngineHost::SetupEngine: - setupEngine(); - break; - case IPCEngineHost::SetupInferior: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - QString executable; - QStringList arguments; - QStringList environment; - s >> executable; - s >> arguments; - s >> environment; - setupInferior(executable, arguments, environment); - } - break; - case IPCEngineHost::RunEngine: - runEngine(); - break; - case IPCEngineHost::ShutdownInferior: - shutdownInferior(); - break; - case IPCEngineHost::ShutdownEngine: - shutdownEngine(); - break; - case IPCEngineHost::DetachDebugger: - detachDebugger(); - break; - case IPCEngineHost::ExecuteStep: - executeStep(); - break; - case IPCEngineHost::ExecuteStepOut: - executeStepOut(); - break; - case IPCEngineHost::ExecuteNext: - executeNext(); - break; - case IPCEngineHost::ExecuteStepI: - executeStepI(); - break; - case IPCEngineHost::ExecuteNextI: - executeNextI(); - break; - case IPCEngineHost::ContinueInferior: - continueInferior(); - break; - case IPCEngineHost::InterruptInferior: - interruptInferior(); - break; - case IPCEngineHost::ExecuteRunToLine: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - ContextData data; - s >> data.fileName; - s >> data.lineNumber; - executeRunToLine(data); - } - break; - case IPCEngineHost::ExecuteRunToFunction: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - QString functionName; - s >> functionName; - executeRunToFunction(functionName); - } - break; - case IPCEngineHost::ExecuteJumpToLine: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - ContextData data; - s >> data.fileName; - s >> data.lineNumber; - executeJumpToLine(data); - } - break; - case IPCEngineHost::ActivateFrame: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 id; - s >> id; - activateFrame(id); - } - break; - case IPCEngineHost::SelectThread: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 id; - s >> id; - selectThread(id); - } - break; - case IPCEngineHost::Disassemble: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 pc; - s >> pc; - disassemble(pc); - } - break; - case IPCEngineHost::AddBreakpoint: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - BreakpointModelId id; - BreakpointParameters d; - s >> id; - s >> d; - addBreakpoint(id, d); - } - break; - case IPCEngineHost::RemoveBreakpoint: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - BreakpointModelId id; - s >> id; - removeBreakpoint(id); - } - break; - case IPCEngineHost::ChangeBreakpoint: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - BreakpointModelId id; - BreakpointParameters d; - s >> id; - s >> d; - changeBreakpoint(id, d); - } - break; - case IPCEngineHost::RequestUpdateWatchData: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - WatchData data; - s >> data; - requestUpdateWatchData(data); - } - break; - case IPCEngineHost::FetchFrameSource: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - qint64 id; - s >> id; - fetchFrameSource(id); - } - break; - }; -} - -DebuggerState IPCEngineGuest::state() const -{ - return m_state; -} - -void IPCEngineGuest::notifyEngineSetupOk() -{ - rpcCall(NotifyEngineSetupOk); -} - -void IPCEngineGuest::notifyEngineSetupFailed() -{ - rpcCall(NotifyEngineSetupFailed); -} - -void IPCEngineGuest::notifyEngineRunFailed() -{ - rpcCall(NotifyEngineRunFailed); -} - -void IPCEngineGuest::notifyInferiorSetupOk() -{ - rpcCall(NotifyInferiorSetupOk); -} - -void IPCEngineGuest::notifyInferiorSetupFailed() -{ - rpcCall(NotifyInferiorSetupFailed); -} - -void IPCEngineGuest::notifyEngineRunAndInferiorRunOk() -{ - rpcCall(NotifyEngineRunAndInferiorRunOk); -} - -void IPCEngineGuest::notifyEngineRunAndInferiorStopOk() -{ - rpcCall(NotifyEngineRunAndInferiorStopOk); -} - -void IPCEngineGuest::notifyInferiorRunRequested() -{ - rpcCall(NotifyInferiorRunRequested); -} - -void IPCEngineGuest::notifyInferiorRunOk() -{ - rpcCall(NotifyInferiorRunOk); -} - -void IPCEngineGuest::notifyInferiorRunFailed() -{ - rpcCall(NotifyInferiorRunFailed); -} - -void IPCEngineGuest::notifyInferiorStopOk() -{ - rpcCall(NotifyInferiorStopOk); -} - -void IPCEngineGuest::notifyInferiorSpontaneousStop() -{ - rpcCall(NotifyInferiorSpontaneousStop); -} - -void IPCEngineGuest::notifyInferiorStopFailed() -{ - rpcCall(NotifyInferiorStopFailed); -} - -void IPCEngineGuest::notifyInferiorExited() -{ - rpcCall(NotifyInferiorExited); -} - -void IPCEngineGuest::notifyInferiorShutdownOk() -{ - rpcCall(NotifyInferiorShutdownOk); -} - -void IPCEngineGuest::notifyInferiorShutdownFailed() -{ - rpcCall(NotifyInferiorShutdownFailed); -} - -void IPCEngineGuest::notifyEngineSpontaneousShutdown() -{ - rpcCall(NotifyEngineSpontaneousShutdown); -} - -void IPCEngineGuest::notifyEngineShutdownOk() -{ - rpcCall(NotifyEngineShutdownOk); -} - -void IPCEngineGuest::notifyEngineShutdownFailed() -{ - rpcCall(NotifyEngineShutdownFailed); -} - -void IPCEngineGuest::notifyInferiorIll() -{ - rpcCall(NotifyInferiorIll); -} - -void IPCEngineGuest::notifyEngineIll() -{ - rpcCall(NotifyEngineIll); -} - -void IPCEngineGuest::notifyInferiorPid(qint64 pid) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << pid; - } - rpcCall(NotifyInferiorPid, p); -} - -void IPCEngineGuest::showStatusMessage(const QString &msg, quint64 timeout) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << msg; - s << (qint64)timeout; - } - rpcCall(ShowStatusMessage, p); -} - -void IPCEngineGuest::showMessage(const QString &msg, quint16 channel, quint64 timeout) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << msg; - s << (qint64)channel; - s << (qint64)timeout; - } - rpcCall(ShowMessage, p); -} - -void IPCEngineGuest::currentFrameChanged(qint64 osid) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << osid; - } - rpcCall(CurrentFrameChanged, p); -} - -void IPCEngineGuest::currentThreadChanged(qint64 osid) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << osid; - } - rpcCall(CurrentThreadChanged, p); -} - -void IPCEngineGuest::listFrames(const StackFrames &frames) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << frames; - } - rpcCall(ListFrames, p); -} - -void IPCEngineGuest::listThreads(const Threads &threads) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << threads; - } - rpcCall(ListThreads, p); -} - -void IPCEngineGuest::disassembled(quint64 pc, const DisassemblerLines &da) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << pc; - s << da; - } - rpcCall(Disassembled, p); -} - -void IPCEngineGuest::notifyAddBreakpointOk(BreakpointModelId id) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id; - } - rpcCall(NotifyAddBreakpointOk, p); -} - -void IPCEngineGuest::notifyAddBreakpointFailed(BreakpointModelId id) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id; - } - rpcCall(NotifyAddBreakpointFailed, p); -} - -void IPCEngineGuest::notifyRemoveBreakpointOk(BreakpointModelId id) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id; - } - rpcCall(NotifyRemoveBreakpointOk, p); -} - -void IPCEngineGuest::notifyRemoveBreakpointFailed(BreakpointModelId id) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id; - } - rpcCall(NotifyRemoveBreakpointFailed, p); -} - -void IPCEngineGuest::notifyChangeBreakpointOk(BreakpointModelId id) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id; - } - rpcCall(NotifyChangeBreakpointOk, p); -} - -void IPCEngineGuest::notifyChangeBreakpointFailed(BreakpointModelId id) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id; - } - rpcCall(NotifyChangeBreakpointFailed, p); -} - -void IPCEngineGuest::notifyBreakpointAdjusted(BreakpointModelId id, - const BreakpointParameters &bp) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id << bp; - } - rpcCall(NotifyBreakpointAdjusted, p); -} - -void IPCEngineGuest::updateWatchData(bool fullCycle, const QList<WatchData> &wd) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << fullCycle; - s << quint64(wd.count()); - for (int i = 0; i < wd.count(); ++i) - s << wd.at(i); - } - rpcCall(UpdateWatchData, p); -} - -void IPCEngineGuest::frameSourceFetched(qint64 id, const QString &name, const QString &source) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id; - s << name; - s << source; - } - rpcCall(FrameSourceFetched, p); -} - -} // namespace Internal -} // namespace Debugger - - diff --git a/src/plugins/debugger/lldblib/ipcengineguest.h b/src/plugins/debugger/lldblib/ipcengineguest.h deleted file mode 100644 index 505328aa85..0000000000 --- a/src/plugins/debugger/lldblib/ipcengineguest.h +++ /dev/null @@ -1,191 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#ifndef IPCENGINEGUEST_H -#define IPCENGINEGUEST_H - -#include <debugger/breakhandler.h> -#include <debugger/debuggerengine.h> -#include <debugger/disassemblerlines.h> -#include <debugger/stackhandler.h> -#include <debugger/threadshandler.h> - -#include <QQueue> -#include <QThread> -#include <QVariant> - -namespace Debugger { -namespace Internal { - -class IPCEngineHost; -class IPCEngineGuest : public QObject -{ - Q_OBJECT - -public: - IPCEngineGuest(); - virtual ~IPCEngineGuest(); - - void setLocalHost(IPCEngineHost *); - void setHostDevice(QIODevice *); - - virtual void nuke() = 0; - virtual void setupEngine() = 0; - virtual void setupInferior(const QString &executeable, - const QStringList &arguments, const QStringList &environment) = 0; - virtual void runEngine() = 0; - virtual void shutdownInferior() = 0; - virtual void shutdownEngine() = 0; - virtual void detachDebugger() = 0; - virtual void executeStep() = 0; - virtual void executeStepOut() = 0; - virtual void executeNext() = 0; - virtual void executeStepI() = 0; - virtual void executeNextI() = 0; - virtual void continueInferior() = 0; - virtual void interruptInferior() = 0; - virtual void executeRunToLine(const ContextData &data) = 0; - virtual void executeRunToFunction(const QString &functionName) = 0; - virtual void executeJumpToLine(const ContextData &data) = 0; - virtual void activateFrame(qint64 token) = 0; - virtual void selectThread(qint64 token) = 0; - virtual void disassemble(quint64 pc) = 0; - virtual void addBreakpoint(BreakpointModelId id, const BreakpointParameters &bp) = 0; - virtual void removeBreakpoint(BreakpointModelId id) = 0; - virtual void changeBreakpoint(BreakpointModelId id, const BreakpointParameters &bp) = 0; - virtual void requestUpdateWatchData(const WatchData &data, - const WatchUpdateFlags & flags = WatchUpdateFlags()) = 0; - virtual void fetchFrameSource(qint64 frame) = 0; - - enum Function - { - NotifyEngineSetupOk = 1, - NotifyEngineSetupFailed = 2, - NotifyEngineRunFailed = 3, - NotifyInferiorSetupOk = 4, - NotifyInferiorSetupFailed = 5, - NotifyEngineRunAndInferiorRunOk = 6, - NotifyEngineRunAndInferiorStopOk = 7, - NotifyInferiorRunRequested = 8, - NotifyInferiorRunOk = 9, - NotifyInferiorRunFailed = 10, - NotifyInferiorStopOk = 11, - NotifyInferiorSpontaneousStop = 12, - NotifyInferiorStopFailed = 13, - NotifyInferiorExited = 14, - NotifyInferiorShutdownOk = 15, - NotifyInferiorShutdownFailed = 16, - NotifyEngineSpontaneousShutdown = 17, - NotifyEngineShutdownOk = 18, - NotifyEngineShutdownFailed = 19, - NotifyInferiorIll = 20, - NotifyEngineIll = 21, - NotifyInferiorPid = 22, - ShowStatusMessage = 23, - ShowMessage = 24, - CurrentFrameChanged = 25, - CurrentThreadChanged = 26, - ListFrames = 27, - ListThreads = 28, - Disassembled = 29, - NotifyAddBreakpointOk = 30, - NotifyAddBreakpointFailed = 31, - NotifyRemoveBreakpointOk = 32, - NotifyRemoveBreakpointFailed = 33, - NotifyChangeBreakpointOk = 34, - NotifyChangeBreakpointFailed = 35, - NotifyBreakpointAdjusted = 36, - UpdateWatchData = 47, - FrameSourceFetched = 48 - }; - Q_ENUMS(Function) - - DebuggerState state() const; - void notifyEngineSetupOk(); - void notifyEngineSetupFailed(); - void notifyEngineRunFailed(); - void notifyInferiorSetupOk(); - void notifyInferiorSetupFailed(); - void notifyEngineRunAndInferiorRunOk(); - void notifyEngineRunAndInferiorStopOk(); - void notifyInferiorRunRequested(); - void notifyInferiorRunOk(); - void notifyInferiorRunFailed(); - void notifyInferiorStopOk(); - void notifyInferiorSpontaneousStop(); - void notifyInferiorStopFailed(); - void notifyInferiorExited(); - void notifyInferiorShutdownOk(); - void notifyInferiorShutdownFailed(); - void notifyEngineSpontaneousShutdown(); - void notifyEngineShutdownOk(); - void notifyEngineShutdownFailed(); - void notifyInferiorIll(); - void notifyEngineIll(); - void notifyInferiorPid(qint64 pid); - void showMessage(const QString &msg, quint16 channel = LogDebug, quint64 timeout = quint64(-1)); - void showStatusMessage(const QString &msg, quint64 timeout = quint64(-1)); - - void currentFrameChanged(qint64 token); - void currentThreadChanged(qint64 token); - void listFrames(const StackFrames &); - void listThreads(const Threads &); - void disassembled(quint64 pc, const DisassemblerLines &da); - - void notifyAddBreakpointOk(BreakpointModelId id); - void notifyAddBreakpointFailed(BreakpointModelId id); - void notifyRemoveBreakpointOk(BreakpointModelId id); - void notifyRemoveBreakpointFailed(BreakpointModelId id); - void notifyChangeBreakpointOk(BreakpointModelId id); - void notifyChangeBreakpointFailed(BreakpointModelId id); - void notifyBreakpointAdjusted(BreakpointModelId id, const BreakpointParameters &bp); - - void updateWatchData(bool fullCycle, const QList<WatchData> &); - - void frameSourceFetched(qint64 frame, const QString &name, const QString &sourceCode); - - void rpcCall(Function f, QByteArray payload = QByteArray()); -public slots: - void rpcCallback(quint64 f, QByteArray payload = QByteArray()); -private slots: - void readyRead(); -private: - IPCEngineHost *m_local_host; - quint64 m_nextMessageCookie; - quint64 m_nextMessageFunction; - quint64 m_nextMessagePayloadSize; - quint64 m_cookie; - QIODevice *m_device; - DebuggerState m_state; -}; - -} // namespace Internal -} // namespace Debugger - -#endif // IPCENGINEGUEST_H diff --git a/src/plugins/debugger/lldblib/ipcenginehost.cpp b/src/plugins/debugger/lldblib/ipcenginehost.cpp deleted file mode 100644 index da48218ee3..0000000000 --- a/src/plugins/debugger/lldblib/ipcenginehost.cpp +++ /dev/null @@ -1,661 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "ipcenginehost.h" - -#include "ipcengineguest.h" -#include <debugger/debuggerstartparameters.h> -#include <debugger/breakhandler.h> -#include <debugger/breakpoint.h> -#include <debugger/disassemblerlines.h> -#include <debugger/moduleshandler.h> -#include <debugger/registerhandler.h> -#include <debugger/stackhandler.h> -#include <debugger/watchhandler.h> -#include <debugger/watchutils.h> -#include <debugger/threadshandler.h> -#include <debugger/disassembleragent.h> -#include <debugger/memoryagent.h> -#include <debugger/debuggerstreamops.h> -#include <debugger/debuggercore.h> - -#include <utils/qtcassert.h> - -#include <QSysInfo> -#include <QDebug> -#include <QFileInfo> -#include <QTimer> -#include <QLocalSocket> - -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -#define SET_NATIVE_BYTE_ORDER(x) x.setByteOrder(QDataStream::LittleEndian) -#else -#define SET_NATIVE_BYTE_ORDER(x) x.setByteOrder(QDataStream::BigEndian) -#endif - -namespace Debugger { -namespace Internal { - -IPCEngineHost::IPCEngineHost (const DebuggerStartParameters &startParameters) - : DebuggerEngine(startParameters) - , m_localGuest(0) - , m_nextMessagePayloadSize(0) - , m_cookie(1) - , m_device(0) -{ - connect(this, SIGNAL(stateChanged(Debugger::DebuggerState)), SLOT(m_stateChanged(Debugger::DebuggerState))); -} - -IPCEngineHost::~IPCEngineHost() -{ - delete m_device; -} - -void IPCEngineHost::setLocalGuest(IPCEngineGuest *guest) -{ - m_localGuest = guest; -} - -void IPCEngineHost::setGuestDevice(QIODevice *device) -{ - if (m_device) { - disconnect(m_device, SIGNAL(readyRead()), this, SLOT(readyRead())); - delete m_device; - } - m_device = device; - if (m_device) - connect(m_device, SIGNAL(readyRead()), this, SLOT(readyRead())); -} - -void IPCEngineHost::setupEngine() -{ - QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); - rpcCall(SetupEngine); -} - -void IPCEngineHost::setupInferior() -{ - QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << QFileInfo(startParameters().executable).absoluteFilePath(); - s << startParameters().processArgs; - s << startParameters().environment.toStringList(); - } - rpcCall(SetupInferior, p); -} - -void IPCEngineHost::runEngine() -{ - QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); - rpcCall(RunEngine); -} - -void IPCEngineHost::shutdownInferior() -{ - QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state()); - rpcCall(ShutdownInferior); -} - -void IPCEngineHost::shutdownEngine() -{ - rpcCall(ShutdownEngine); -} - -void IPCEngineHost::detachDebugger() -{ - rpcCall(DetachDebugger); -} - -void IPCEngineHost::executeStep() -{ - rpcCall(ExecuteStep); -} - -void IPCEngineHost::executeStepOut() -{ - rpcCall(ExecuteStepOut); -} - -void IPCEngineHost::executeNext() -{ - rpcCall(ExecuteNext); -} - -void IPCEngineHost::executeStepI() -{ - rpcCall(ExecuteStepI); -} - -void IPCEngineHost::executeNextI() -{ - rpcCall(ExecuteNextI); -} - -void IPCEngineHost::continueInferior() -{ - QTC_ASSERT(state() == InferiorStopOk, qDebug() << state()); - resetLocation(); - rpcCall(ContinueInferior); -} - -void IPCEngineHost::interruptInferior() -{ - QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state()); - rpcCall(InterruptInferior); -} - -void IPCEngineHost::executeRunToLine(const ContextData &data) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << data.fileName; - s << quint64(data.lineNumber); - } - rpcCall(ExecuteRunToLine, p); -} - -void IPCEngineHost::executeRunToFunction(const QString &functionName) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << functionName; - } - rpcCall(ExecuteRunToFunction, p); -} - -void IPCEngineHost::executeJumpToLine(const ContextData &data) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << data.fileName; - s << quint64(data.lineNumber); - } - rpcCall(ExecuteJumpToLine, p); -} - -void IPCEngineHost::activateFrame(int index) -{ - resetLocation(); - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << quint64(index); - } - rpcCall(ActivateFrame, p); -} - -void IPCEngineHost::selectThread(ThreadId id) -{ - resetLocation(); - QTC_ASSERT(id.isValid(), return); - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id.raw(); - } - rpcCall(SelectThread, p); -} - -void IPCEngineHost::fetchDisassembler(DisassemblerAgent *v) -{ - quint64 address = v->location().address(); - m_frameToDisassemblerAgent.insert(address, v); - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << address; - } - rpcCall(Disassemble, p); -} - -void IPCEngineHost::insertBreakpoint(BreakpointModelId id) -{ - breakHandler()->notifyBreakpointInsertProceeding(id); - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id; - s << breakHandler()->breakpointData(id); - } - rpcCall(AddBreakpoint, p); -} - -void IPCEngineHost::removeBreakpoint(BreakpointModelId id) -{ - breakHandler()->notifyBreakpointRemoveProceeding(id); - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id; - } - rpcCall(RemoveBreakpoint, p); -} - -void IPCEngineHost::changeBreakpoint(BreakpointModelId id) -{ - breakHandler()->notifyBreakpointChangeProceeding(id); - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id; - s << breakHandler()->breakpointData(id); - } - rpcCall(RemoveBreakpoint, p); -} - -void IPCEngineHost::updateWatchData(const WatchData &data, - const WatchUpdateFlags &flags) -{ - Q_UNUSED(flags); - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << data; - } - rpcCall(RequestUpdateWatchData, p); -} - -void IPCEngineHost::fetchFrameSource(qint64 id) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << id; - } - rpcCall(FetchFrameSource, p); -} - -void IPCEngineHost::rpcCallback(quint64 f, QByteArray payload) -{ - switch (f) { - default: { - showMessage(QLatin1String("IPC Error: unhandled id in guest to host call")); - const QString logMessage = tr("Fatal engine shutdown. Incompatible binary or IPC error."); - showMessage(logMessage, LogError); - showStatusMessage(logMessage); - } - nuke(); - break; - case IPCEngineGuest::NotifyEngineSetupOk: - notifyEngineSetupOk(); - break; - case IPCEngineGuest::NotifyEngineSetupFailed: - notifyEngineSetupFailed(); - break; - case IPCEngineGuest::NotifyEngineRunFailed: - notifyEngineRunFailed(); - break; - case IPCEngineGuest::NotifyInferiorSetupOk: - attemptBreakpointSynchronization(); - notifyInferiorSetupOk(); - break; - case IPCEngineGuest::NotifyInferiorSetupFailed: - notifyInferiorSetupFailed(); - break; - case IPCEngineGuest::NotifyEngineRunAndInferiorRunOk: - notifyEngineRunAndInferiorRunOk(); - break; - case IPCEngineGuest::NotifyEngineRunAndInferiorStopOk: - notifyEngineRunAndInferiorStopOk(); - break; - case IPCEngineGuest::NotifyInferiorRunRequested: - notifyInferiorRunRequested(); - break; - case IPCEngineGuest::NotifyInferiorRunOk: - notifyInferiorRunOk(); - break; - case IPCEngineGuest::NotifyInferiorRunFailed: - notifyInferiorRunFailed(); - break; - case IPCEngineGuest::NotifyInferiorStopOk: - notifyInferiorStopOk(); - break; - case IPCEngineGuest::NotifyInferiorSpontaneousStop: - notifyInferiorSpontaneousStop(); - break; - case IPCEngineGuest::NotifyInferiorStopFailed: - notifyInferiorStopFailed(); - break; - case IPCEngineGuest::NotifyInferiorExited: - notifyInferiorExited(); - break; - case IPCEngineGuest::NotifyInferiorShutdownOk: - notifyInferiorShutdownOk(); - break; - case IPCEngineGuest::NotifyInferiorShutdownFailed: - notifyInferiorShutdownFailed(); - break; - case IPCEngineGuest::NotifyEngineSpontaneousShutdown: - notifyEngineSpontaneousShutdown(); - break; - case IPCEngineGuest::NotifyEngineShutdownOk: - notifyEngineShutdownOk(); - break; - case IPCEngineGuest::NotifyEngineShutdownFailed: - notifyEngineShutdownFailed(); - break; - case IPCEngineGuest::NotifyInferiorIll: - notifyInferiorIll(); - break; - case IPCEngineGuest::NotifyEngineIll: - notifyEngineIll(); - break; - case IPCEngineGuest::NotifyInferiorPid: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 pid; - s >> pid; - notifyInferiorPid(pid); - } - break; - case IPCEngineGuest::ShowStatusMessage: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - QString msg; - qint64 timeout; - s >> msg; - s >> timeout; - showStatusMessage(msg, timeout); - } - break; - case IPCEngineGuest::ShowMessage: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - QString msg; - qint16 channel; - qint64 timeout; - s >> msg; - s >> channel; - s >> timeout; - showMessage(msg, channel, timeout); - } - break; - case IPCEngineGuest::CurrentFrameChanged: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 token; - s >> token; - - resetLocation(); - StackHandler *sh = stackHandler(); - sh->setCurrentIndex(token); - if (!sh->currentFrame().isUsable() || QFileInfo(sh->currentFrame().file).exists()) - gotoLocation(Location(sh->currentFrame(), true)); - else if (!m_sourceAgents.contains(sh->currentFrame().file)) - fetchFrameSource(token); - foreach (SourceAgent *agent, m_sourceAgents.values()) - agent->updateLocationMarker(); - } - break; - case IPCEngineGuest::CurrentThreadChanged: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 token; - s >> token; - threadsHandler()->setCurrentThread(ThreadId(token)); - } - break; - case IPCEngineGuest::ListFrames: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - StackFrames frames; - s >> frames; - stackHandler()->setFrames(frames); - } - break; - case IPCEngineGuest::ListThreads: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - Threads threads; - s >> threads; - threadsHandler()->setThreads(threads); - } - break; - case IPCEngineGuest::Disassembled: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 pc; - DisassemblerLines lines; - s >> pc; - s >> lines; - DisassemblerAgent *view = m_frameToDisassemblerAgent.take(pc); - if (view) - view->setContents(lines); - } - break; - case IPCEngineGuest::UpdateWatchData: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - bool fullCycle; - qint64 count; - QList<WatchData> wd; - s >> fullCycle; - s >> count; - for (qint64 i = 0; i < count; ++i) { - WatchData d; - s >> d; - wd.append(d); - } - WatchHandler *wh = watchHandler(); - if (!wh) - break; - wh->insertData(wd); - } - break; - case IPCEngineGuest::NotifyAddBreakpointOk: - { - attemptBreakpointSynchronization(); - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 d; - s >> d; - BreakpointModelId id = BreakpointModelId::fromInternalId(d); - breakHandler()->notifyBreakpointInsertOk(id); - } - break; - case IPCEngineGuest::NotifyAddBreakpointFailed: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 d; - s >> d; - BreakpointModelId id = BreakpointModelId::fromInternalId(d); - breakHandler()->notifyBreakpointInsertFailed(id); - } - break; - case IPCEngineGuest::NotifyRemoveBreakpointOk: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 d; - s >> d; - BreakpointModelId id = BreakpointModelId::fromInternalId(d); - breakHandler()->notifyBreakpointRemoveOk(id); - } - break; - case IPCEngineGuest::NotifyRemoveBreakpointFailed: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 d; - s >> d; - BreakpointModelId id = BreakpointModelId::fromInternalId(d); - breakHandler()->notifyBreakpointRemoveFailed(id); - } - break; - case IPCEngineGuest::NotifyChangeBreakpointOk: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 d; - s >> d; - BreakpointModelId id = BreakpointModelId::fromInternalId(d); - breakHandler()->notifyBreakpointChangeOk(id); - } - break; - case IPCEngineGuest::NotifyChangeBreakpointFailed: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 d; - s >> d; - BreakpointModelId id = BreakpointModelId::fromInternalId(d); - breakHandler()->notifyBreakpointChangeFailed(id); - } - break; - case IPCEngineGuest::NotifyBreakpointAdjusted: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - quint64 dd; - BreakpointParameters d; - s >> dd >> d; - BreakpointModelId id = BreakpointModelId::fromInternalId(dd); - breakHandler()->notifyBreakpointAdjusted(id, d); - } - break; - case IPCEngineGuest::FrameSourceFetched: - { - QDataStream s(payload); - SET_NATIVE_BYTE_ORDER(s); - qint64 token; - QString path; - QString source; - s >> token >> path >> source; - SourceAgent *agent = new SourceAgent(this); - agent->setSourceProducerName(startParameters().connParams.host); - agent->setContent(path, source); - m_sourceAgents.insert(path, agent); - agent->updateLocationMarker(); - } - break; - } -} - -void IPCEngineHost::m_stateChanged(Debugger::DebuggerState state) -{ - QByteArray p; - { - QDataStream s(&p, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << (qint64)state; - } - rpcCall(StateChanged, p); - -} - -void IPCEngineHost::rpcCall(Function f, QByteArray payload) -{ - if (m_localGuest) { - QMetaObject::invokeMethod(m_localGuest, - "rpcCallback", - Qt::QueuedConnection, - Q_ARG(quint64, f), - Q_ARG(QByteArray, payload)); - } else if (m_device) { - QByteArray header; - { - QDataStream s(&header, QIODevice::WriteOnly); - SET_NATIVE_BYTE_ORDER(s); - s << m_cookie++; - s << (quint64) f; - s << (quint64) payload.size(); - } - m_device->write(header); - m_device->write(payload); - m_device->putChar('T'); - QLocalSocket *sock = qobject_cast<QLocalSocket *>(m_device); - if (sock) - sock->flush(); - } -} - -void IPCEngineHost::readyRead() -{ - QDataStream s(m_device); - SET_NATIVE_BYTE_ORDER(s); - if (!m_nextMessagePayloadSize) { - if (quint64(m_device->bytesAvailable ()) < 3 * sizeof(quint64)) - return; - s >> m_nextMessageCookie; - s >> m_nextMessageFunction; - s >> m_nextMessagePayloadSize; - m_nextMessagePayloadSize += 1; // Terminator and "got header" marker. - } - - quint64 ba = m_device->bytesAvailable(); - if (ba < m_nextMessagePayloadSize) - return; - - QByteArray payload = m_device->read(m_nextMessagePayloadSize - 1); - - char terminator; - m_device->getChar(&terminator); - if (terminator != 'T') { - showStatusMessage(tr("Fatal engine shutdown. Incompatible binary or IPC error.")); - showMessage(QLatin1String("IPC Error: terminator missing")); - nuke(); - return; - } - rpcCallback(m_nextMessageFunction, payload); - m_nextMessagePayloadSize = 0; - if (quint64(m_device->bytesAvailable()) >= 3 * sizeof(quint64)) - QTimer::singleShot(0, this, SLOT(readyRead())); -} - -} // namespace Internal -} // namespace Debugger - - diff --git a/src/plugins/debugger/lldblib/ipcenginehost.h b/src/plugins/debugger/lldblib/ipcenginehost.h deleted file mode 100644 index 92f847ca44..0000000000 --- a/src/plugins/debugger/lldblib/ipcenginehost.h +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#ifndef DEBUGGER_IPCENGINE_HOST_H -#define DEBUGGER_IPCENGINE_HOST_H - -#include <debugger/debuggerengine.h> -#include <debugger/threadshandler.h> -#include <debugger/stackhandler.h> -#include <debugger/breakhandler.h> -#include <debugger/sourceagent.h> - -#include <QQueue> -#include <QVariant> -#include <QThread> - -namespace Debugger { -namespace Internal { - -class IPCEngineGuest; -class IPCEngineHost : public DebuggerEngine -{ - Q_OBJECT - -public: - explicit IPCEngineHost(const DebuggerStartParameters &startParameters); - ~IPCEngineHost(); - - // use either one - void setLocalGuest(IPCEngineGuest *); - void setGuestDevice(QIODevice *); - - enum Function - { - SetupIPC = 1, - StateChanged = 2, - SetupEngine = 3, - SetupInferior = 4, - RunEngine = 5, - ShutdownInferior = 6, - ShutdownEngine = 7, - DetachDebugger = 8, - ExecuteStep = 9, - ExecuteStepOut = 10, - ExecuteNext = 11, - ExecuteStepI = 12, - ExecuteNextI = 13, - ContinueInferior = 14, - InterruptInferior = 15, - ExecuteRunToLine = 16, - ExecuteRunToFunction = 17, - ExecuteJumpToLine = 18, - ActivateFrame = 19, - SelectThread = 20, - Disassemble = 21, - AddBreakpoint = 22, - RemoveBreakpoint = 23, - ChangeBreakpoint = 24, - RequestUpdateWatchData = 25, - FetchFrameSource = 26 - }; - Q_ENUMS(Function) - - void setupEngine(); - void setupInferior(); - void runEngine(); - void shutdownInferior(); - void shutdownEngine(); - void detachDebugger(); - void executeStep(); - void executeStepOut() ; - void executeNext(); - void executeStepI(); - void executeNextI(); - void continueInferior(); - void interruptInferior(); - void executeRunToLine(const ContextData &data); - void executeRunToFunction(const QString &functionName); - void executeJumpToLine(const ContextData &data); - void activateFrame(int index); - void selectThread(ThreadId index); - void fetchDisassembler(DisassemblerAgent *); - bool acceptsBreakpoint(BreakpointModelId) const { return true; } // FIXME - void insertBreakpoint(BreakpointModelId id); - void removeBreakpoint(BreakpointModelId id); - void changeBreakpoint(BreakpointModelId id); - void updateWatchData(const WatchData &data, - const WatchUpdateFlags &flags = WatchUpdateFlags()); - void fetchFrameSource(qint64 id); - bool hasCapability(unsigned) const { return false; } - - void rpcCall(Function f, QByteArray payload = QByteArray()); -protected: - virtual void nuke() = 0; -public slots: - void rpcCallback(quint64 f, QByteArray payload = QByteArray()); -private slots: - void m_stateChanged(Debugger::DebuggerState state); - void readyRead(); -private: - IPCEngineGuest *m_localGuest; - quint64 m_nextMessageCookie; - quint64 m_nextMessageFunction; - quint64 m_nextMessagePayloadSize; - quint64 m_cookie; - QIODevice *m_device; - QHash<quint64, DisassemblerAgent *> m_frameToDisassemblerAgent; - QHash<QString, SourceAgent *> m_sourceAgents; -}; - -} // namespace Internal -} // namespace Debugger - -#endif // DEBUGGER_LLDBENGINE_H diff --git a/src/plugins/debugger/lldblib/lldbenginehost.cpp b/src/plugins/debugger/lldblib/lldbenginehost.cpp deleted file mode 100644 index 538ba66e12..0000000000 --- a/src/plugins/debugger/lldblib/lldbenginehost.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "lldbenginehost.h" - -#include <debugger/debuggerstartparameters.h> -#include <debugger/debuggeractions.h> -#include <debugger/debuggerconstants.h> -#include <debugger/debuggerdialogs.h> -#include <debugger/debuggerplugin.h> -#include <debugger/debuggerstringutils.h> - -#include <debugger/breakhandler.h> -#include <debugger/breakpoint.h> -#include <debugger/moduleshandler.h> -#include <debugger/registerhandler.h> -#include <debugger/stackhandler.h> -#include <debugger/watchhandler.h> -#include <debugger/watchutils.h> -#include <debugger/threadshandler.h> -#include <debugger/disassembleragent.h> -#include <debugger/memoryagent.h> - -#include <coreplugin/icore.h> -#include <utils/qtcassert.h> - -#include <QDebug> -#include <QProcess> -#include <QFileInfo> -#include <QThread> -#include <QCoreApplication> - -namespace Debugger { -namespace Internal { - -SshIODevice::SshIODevice(QSsh::SshRemoteProcessRunner *r) - : runner(r) - , buckethead(0) -{ - setOpenMode(QIODevice::ReadWrite | QIODevice::Unbuffered); - connect (runner, SIGNAL(processStarted()), this, SLOT(processStarted())); - connect(runner, SIGNAL(readyReadStandardOutput()), this, SLOT(outputAvailable())); - connect(runner, SIGNAL(readyReadStandardError()), this, SLOT(errorOutputAvailable())); -} - -SshIODevice::~SshIODevice() -{ - delete runner; -} - -qint64 SshIODevice::bytesAvailable () const -{ - qint64 r = QIODevice::bytesAvailable(); - foreach (const QByteArray &bucket, buckets) - r += bucket.size(); - r-= buckethead; - return r; -} -qint64 SshIODevice::writeData (const char * data, qint64 maxSize) -{ - if (proc == 0) { - startupbuffer += QByteArray::fromRawData(data, maxSize); - return maxSize; - } - proc->write(data, maxSize); - return maxSize; -} -qint64 SshIODevice::readData (char * data, qint64 maxSize) -{ - if (proc == 0) - return 0; - qint64 size = maxSize; - while (size > 0) { - if (!buckets.size()) - return maxSize - size; - QByteArray &bucket = buckets.head(); - if ((size + buckethead) >= bucket.size()) { - int d = bucket.size() - buckethead; - memcpy(data, bucket.data() + buckethead, d); - data += d; - size -= d; - buckets.dequeue(); - buckethead = 0; - } else { - memcpy(data, bucket.data() + buckethead, size); - data += size; - buckethead += size; - size = 0; - } - } - return maxSize - size; -} - -void SshIODevice::processStarted() -{ - runner->writeDataToProcess(startupbuffer); -} - -void SshIODevice::outputAvailable() -{ - buckets.enqueue(runner->readAllStandardOutput()); - emit readyRead(); -} - -void SshIODevice::errorOutputAvailable() -{ - fprintf(stderr, "%s", runner->readAllStandardError().data()); -} - - -LldbEngineHost::LldbEngineHost(const DebuggerStartParameters &startParameters) - :IPCEngineHost(startParameters), m_ssh(0) -{ - showMessage(QLatin1String("setting up coms")); - setObjectName(QLatin1String("LLDBEngine")); - - if (startParameters.startMode == StartRemoteEngine) - { - m_guestProcess = 0; - QSsh::SshRemoteProcessRunner * const runner = new QSsh::SshRemoteProcessRunner; - connect (runner, SIGNAL(connectionError(QSsh::SshError)), - this, SLOT(sshConnectionError(QSsh::SshError))); - runner->run(startParameters.serverStartScript.toUtf8(), startParameters.connParams); - setGuestDevice(new SshIODevice(runner)); - } else { - m_guestProcess = new QProcess(this); - - connect(m_guestProcess, SIGNAL(finished(int,QProcess::ExitStatus)), - this, SLOT(finished(int,QProcess::ExitStatus))); - - connect(m_guestProcess, SIGNAL(readyReadStandardError()), this, - SLOT(stderrReady())); - - - QString a = Core::ICore::resourcePath() + QLatin1String("/qtcreator-lldb"); - if (getenv("QTC_LLDB_GUEST") != 0) - a = QString::fromLocal8Bit(getenv("QTC_LLDB_GUEST")); - - showStatusMessage(QString(QLatin1String("starting %1")).arg(a)); - - m_guestProcess->start(a, QStringList(), QIODevice::ReadWrite | QIODevice::Unbuffered); - m_guestProcess->setReadChannel(QProcess::StandardOutput); - - if (!m_guestProcess->waitForStarted()) { - showStatusMessage(tr("qtcreator-lldb failed to start: %1").arg(m_guestProcess->errorString())); - notifyEngineSpontaneousShutdown(); - return; - } - - setGuestDevice(m_guestProcess); - } -} - -LldbEngineHost::~LldbEngineHost() -{ - showMessage(QLatin1String("tear down qtcreator-lldb")); - - if (m_guestProcess) { - disconnect(m_guestProcess, SIGNAL(finished(int,QProcess::ExitStatus)), - this, SLOT(finished(int,QProcess::ExitStatus))); - - - m_guestProcess->terminate(); - m_guestProcess->kill(); - } - if (m_ssh && m_ssh->isProcessRunning()) { - // TODO: openssh doesn't do that - - m_ssh->sendSignalToProcess(QSsh::SshRemoteProcess::KillSignal); - } -} - -void LldbEngineHost::nuke() -{ - stderrReady(); - showMessage(QLatin1String("Nuke engaged. Bug in Engine/IPC or incompatible IPC versions. "), LogError); - showStatusMessage(tr("Fatal engine shutdown. Consult debugger log for details.")); - m_guestProcess->terminate(); - m_guestProcess->kill(); - notifyEngineSpontaneousShutdown(); -} -void LldbEngineHost::sshConnectionError(QSsh::SshError e) -{ - showStatusMessage(tr("SSH connection error: %1").arg(e)); -} - -void LldbEngineHost::finished(int, QProcess::ExitStatus status) -{ - showMessage(QString(QLatin1String("guest went bye bye. exit status: %1 and code: %2")) - .arg(status).arg(m_guestProcess->exitCode()), LogError); - nuke(); -} - -void LldbEngineHost::stderrReady() -{ - fprintf(stderr,"%s", m_guestProcess->readAllStandardError().data()); -} - -DebuggerEngine *createLldbLibEngine(const DebuggerStartParameters &startParameters) -{ - return new LldbEngineHost(startParameters); -} - -} // namespace Internal -} // namespace Debugger - diff --git a/src/plugins/debugger/lldblib/lldbenginehost.h b/src/plugins/debugger/lldblib/lldbenginehost.h deleted file mode 100644 index 52df2b373e..0000000000 --- a/src/plugins/debugger/lldblib/lldbenginehost.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#ifndef DEBUGGER_LLDBENGINE_HOST_H -#define DEBUGGER_LLDBENGINE_HOST_H - -#include "ipcenginehost.h" -#include <ssh/ssherrors.h> -#include <ssh/sshconnection.h> -#include <ssh/sshremoteprocess.h> -#include <ssh/sshremoteprocessrunner.h> - -#include <QProcess> -#include <QQueue> - -namespace Debugger { -namespace Internal { - -class SshIODevice : public QIODevice -{ -Q_OBJECT -public: - SshIODevice(QSsh::SshRemoteProcessRunner *r); - ~SshIODevice(); - virtual qint64 bytesAvailable () const; - virtual qint64 writeData (const char * data, qint64 maxSize); - virtual qint64 readData (char * data, qint64 maxSize); -private slots: - void processStarted(); - void outputAvailable(); - void errorOutputAvailable(); -private: - QSsh::SshRemoteProcessRunner *runner; - QSsh::SshRemoteProcess::Ptr proc; - int buckethead; - QQueue<QByteArray> buckets; - QByteArray startupbuffer; -}; - -class LldbEngineHost : public IPCEngineHost -{ - Q_OBJECT - -public: - explicit LldbEngineHost(const DebuggerStartParameters &startParameters); - ~LldbEngineHost(); - -private: - QProcess *m_guestProcess; - QSsh::SshRemoteProcessRunner *m_ssh; -protected: - void nuke(); -private slots: - void sshConnectionError(QSsh::SshError); - void finished(int, QProcess::ExitStatus); - void stderrReady(); -}; - -} // namespace Internal -} // namespace Debugger - -#endif // DEBUGGER_LLDBENGINE_HOST_H diff --git a/src/plugins/debugger/lldblib/lldbhost.pri b/src/plugins/debugger/lldblib/lldbhost.pri deleted file mode 100644 index 0e9297d7e3..0000000000 --- a/src/plugins/debugger/lldblib/lldbhost.pri +++ /dev/null @@ -1,20 +0,0 @@ -WITH_LLDB = $$(WITH_LLDB) - -HEADERS += $$PWD/ipcenginehost.h \ - $$PWD/lldbenginehost.h - -SOURCES += $$PWD/ipcenginehost.cpp \ - $$PWD/lldbenginehost.cpp - -INCLUDEPATH+= - -FORMS += - -RESOURCES += - -!isEmpty(WITH_LLDB) { - DEFINES += WITH_LLDB - HEADERS += $$PWD/lldboptionspage.h - SOURCES += $$PWD/lldboptionspage.cpp - FORMS += $$PWD/lldboptionspagewidget.ui -} diff --git a/src/plugins/debugger/lldblib/lldboptionspage.cpp b/src/plugins/debugger/lldblib/lldboptionspage.cpp deleted file mode 100644 index 5ce79b33ad..0000000000 --- a/src/plugins/debugger/lldblib/lldboptionspage.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "lldboptionspage.h" -#include <debugger/debuggerconstants.h> -#include <debugger/debuggerinternalconstants.h> - -#include <coreplugin/icore.h> - -#include <QCoreApplication> -#include <QUrl> -#include <QTextStream> -#include <QMessageBox> -#include <QDesktopServices> - -namespace Debugger { -namespace Internal { - -LldbOptionsPageWidget::LldbOptionsPageWidget(QWidget *parent, QSettings *s_) - : QWidget(parent) - , s(s_) -{ - m_ui.setupUi(this); - load(); -} - -void LldbOptionsPageWidget::save() -{ - s->beginGroup(QLatin1String("LLDB")); - s->setValue(QLatin1String("enabled"), m_ui.enableLldb->isChecked ()); - s->setValue(QLatin1String("gdbEmu"), m_ui.gdbEmu->isChecked ()); - s->endGroup(); -} - -void LldbOptionsPageWidget::load() -{ - s->beginGroup(QLatin1String("LLDB")); - m_ui.enableLldb->setChecked(s->value(QLatin1String("enabled"), false).toBool()); - m_ui.gdbEmu->setChecked(s->value(QLatin1String("gdbEmu"), true).toBool()); - s->endGroup(); -} - -// ---------- LldbOptionsPage -LldbOptionsPage::LldbOptionsPage() -{ - // m_options->fromSettings(Core::ICore::settings()); - setId("F.Lldb"); - setDisplayName(tr("LLDB")); - setCategory(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY); - setDisplayCategory(QCoreApplication::translate("Debugger", Constants::DEBUGGER_SETTINGS_TR_CATEGORY)); - setCategoryIcon(QLatin1String(Constants::DEBUGGER_COMMON_SETTINGS_CATEGORY_ICON)); -} - -QWidget *LldbOptionsPage::createPage(QWidget *parent) -{ - m_widget = new LldbOptionsPageWidget(parent, Core::ICore::settings()); - return m_widget; -} - -void LldbOptionsPage::apply() -{ - if (!m_widget) - return; - m_widget->save(); -} - -void LldbOptionsPage::finish() -{ -} - -bool LldbOptionsPage::matches(const QString &s) const -{ - return QString(s.toLower()).contains(QLatin1String("lldb")); -} - -void addLldbOptionPages(QList<Core::IOptionsPage *> *opts) -{ - opts->push_back(new LldbOptionsPage); -} - - -} // namespace Internal -} // namespace Debugger diff --git a/src/plugins/debugger/lldblib/lldboptionspagewidget.ui b/src/plugins/debugger/lldblib/lldboptionspagewidget.ui deleted file mode 100644 index 78e77699f0..0000000000 --- a/src/plugins/debugger/lldblib/lldboptionspagewidget.ui +++ /dev/null @@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>Debugger::Internal::LldbOptionsPageWidget</class> - <widget class="QWidget" name="Debugger::Internal::LldbOptionsPageWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>522</width> - <height>512</height> - </rect> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"/> - </item> - <item> - <widget class="QGroupBox" name="enableLldb"> - <property name="title"> - <string>Enable LLDB</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>false</bool> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QCheckBox" name="gdbEmu"> - <property name="text"> - <string>Use GDB Python dumpers</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>203</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/plugins/debugger/localsandexpressionsoptionspage.ui b/src/plugins/debugger/localsandexpressionsoptionspage.ui index ce60b3dfbd..d2b320ddaa 100644 --- a/src/plugins/debugger/localsandexpressionsoptionspage.ui +++ b/src/plugins/debugger/localsandexpressionsoptionspage.ui @@ -60,7 +60,7 @@ <item> <widget class="QCheckBox" name="checkBoxShowStdNamespace"> <property name="toolTip"> - <string>Show 'std::' prefix for types from the standard library.</string> + <string>Shows 'std::' prefix for types from the standard library.</string> </property> <property name="text"> <string>Show "std::" namespace for types</string> @@ -70,7 +70,7 @@ <item> <widget class="QCheckBox" name="checkBoxShowQtNamespace"> <property name="toolTip"> - <string>Show Qt namespace prefix for Qt types. This is only relevant if Qt was configured with '-qtnamespace'.</string> + <string>Shows Qt namespace prefix for Qt types. This is only relevant if Qt was configured with '-qtnamespace'.</string> </property> <property name="text"> <string>Show Qt's namespace for types</string> diff --git a/src/plugins/debugger/sourceagent.cpp b/src/plugins/debugger/sourceagent.cpp index 210528bf13..d944a20b1c 100644 --- a/src/plugins/debugger/sourceagent.cpp +++ b/src/plugins/debugger/sourceagent.cpp @@ -137,7 +137,7 @@ void SourceAgent::updateLocationMarker() QTC_ASSERT(d->editor, return); if (d->locationMark) - d->editor->markableInterface()->removeMark(d->locationMark); + d->editor->textDocument()->markableInterface()->removeMark(d->locationMark); delete d->locationMark; d->locationMark = 0; if (d->engine->stackHandler()->currentFrame().file == d->path) { @@ -145,7 +145,7 @@ void SourceAgent::updateLocationMarker() d->locationMark = new TextEditor::ITextMark(lineNumber); d->locationMark->setIcon(debuggerCore()->locationMarkIcon()); d->locationMark->setPriority(TextEditor::ITextMark::HighPriority); - d->editor->markableInterface()->addMark(d->locationMark); + d->editor->textDocument()->markableInterface()->addMark(d->locationMark); QPlainTextEdit *plainTextEdit = qobject_cast<QPlainTextEdit *>(d->editor->widget()); QTC_ASSERT(plainTextEdit, return); QTextCursor tc = plainTextEdit->textCursor(); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 23a149dab5..84c50ec6d6 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -1230,8 +1230,10 @@ QStringList WatchModel::typeFormatList(const WatchData &data) const << tr("Local 8bit string") << tr("UTF16 string") << tr("UCS4 string") - << tr("Array of 10 items") - << tr("Array of 1000 items"); + << tr("Array of %1 items").arg(10) + << tr("Array of %1 items").arg(100) + << tr("Array of %1 items").arg(1000) + << tr("Array of %1 items").arg(10000); if (data.type.contains("char[") || data.type.contains("char [")) return QStringList() << tr("Latin1 string") diff --git a/src/plugins/designer/gotoslot_test.cpp b/src/plugins/designer/gotoslot_test.cpp index d5f261b668..c8b4d851f0 100644 --- a/src/plugins/designer/gotoslot_test.cpp +++ b/src/plugins/designer/gotoslot_test.cpp @@ -59,22 +59,102 @@ namespace { class MyTestDataDir : public Core::Internal::Tests::TestDataDir { public: + MyTestDataDir() + : TestDataDir(QString()) + {} MyTestDataDir(const QString &dir) : TestDataDir(QLatin1String(SRCDIR "/../../../tests/designer/") + dir) {} }; -QString expectedContentsForFile(const QString &filePath) +class DocumentContainsFunctionDefinition: protected SymbolVisitor +{ +public: + bool operator()(Scope *scope, const QString function) + { + if (!scope) + return false; + + m_referenceFunction = function; + m_result = false; + + accept(scope); + return m_result; + } + +protected: + bool preVisit(Symbol *) { return !m_result; } + + bool visit(Function *symbol) + { + const QString function = m_overview.prettyName(symbol->name()); + if (function == m_referenceFunction) + m_result = true; + return false; + } + +private: + bool m_result; + QString m_referenceFunction; + Overview m_overview; +}; + +class DocumentContainsDeclaration: protected SymbolVisitor +{ +public: + bool operator()(Scope *scope, const QString function) + { + if (!scope) + return false; + + m_referenceFunction = function; + m_result = false; + + accept(scope); + return m_result; + } + +protected: + bool preVisit(Symbol *) { return !m_result; } + + void postVisit(Symbol *symbol) + { + if (symbol->isClass()) + m_currentClass.clear(); + } + + bool visit(Class *symbol) + { + m_currentClass = m_overview.prettyName(symbol->name()); + return true; + } + + bool visit(Declaration *symbol) + { + QString declaration = m_overview.prettyName(symbol->name()); + if (!m_currentClass.isEmpty()) + declaration = m_currentClass + QLatin1String("::") + declaration; + if (m_referenceFunction == declaration) + m_result = true; + return false; + } + +private: + bool m_result; + QString m_referenceFunction; + QString m_currentClass; + Overview m_overview; +}; + +bool documentContainsFunctionDefinition(const Document::Ptr &document, const QString function) +{ + return DocumentContainsFunctionDefinition()(document->globalNamespace(), function); +} + +bool documentContainsMemberFunctionDeclaration(const Document::Ptr &document, + const QString declaration) { - QFileInfo fi(filePath); - const QString referenceFileName = QLatin1String("reference_") + fi.fileName(); - const QString referenceFilePath = fi.dir().absoluteFilePath(referenceFileName); - - Utils::FileReader fileReader; - const bool isFetchOk = fileReader.fetch(referenceFilePath); - if (isFetchOk) - return QString::fromUtf8(fileReader.data()); - return QString(); + return DocumentContainsDeclaration()(document->globalNamespace(), declaration); } class GoToSlotTest @@ -129,8 +209,14 @@ public: } // Compare - QCOMPARE(cppFileEditor->textDocument()->contents(), expectedContentsForFile(cppFile)); - QCOMPARE(hFileEditor->textDocument()->contents(), expectedContentsForFile(hFile)); + const Document::Ptr cppDocument + = m_modelManager->cppEditorSupport(cppFileEditor)->snapshotUpdater()->document(); + const Document::Ptr hDocument + = m_modelManager->cppEditorSupport(hFileEditor)->snapshotUpdater()->document(); + QVERIFY(documentContainsFunctionDefinition(cppDocument, + QLatin1String("Form::on_pushButton_clicked"))); + QVERIFY(documentContainsMemberFunctionDeclaration(hDocument, + QLatin1String("Form::on_pushButton_clicked"))); } private: @@ -152,7 +238,7 @@ private: #endif /// Check: Executes "Go To Slot..." on a QPushButton in a *.ui file and checks if the respective -/// header and source files are updated. +/// header and source files are correctly updated. void Designer::Internal::FormEditorPlugin::test_gotoslot() { #if QT_VERSION >= 0x050000 @@ -165,15 +251,45 @@ void Designer::Internal::FormEditorPlugin::test_gotoslot() #endif } -void FormEditorPlugin::test_gotoslot_data() +void Designer::Internal::FormEditorPlugin::test_gotoslot_data() { +#if QT_VERSION >= 0x050000 typedef QLatin1String _; QTest::addColumn<QStringList>("files"); - MyTestDataDir testData(QLatin1String("gotoslot_withoutProject")); + MyTestDataDir testDataDirWithoutProject(_("gotoslot_withoutProject")); QTest::newRow("withoutProject") << (QStringList() - << testData.file(_("form.cpp")) - << testData.file(_("form.h")) - << testData.file(_("form.ui"))); + << testDataDirWithoutProject.file(_("form.cpp")) + << testDataDirWithoutProject.file(_("form.h")) + << testDataDirWithoutProject.file(_("form.ui"))); + + // Finding the right class for inserting definitions/declarations is based on + // finding a class with a member whose type is the class from the "ui_xxx.h" header. + // In the following test data the header files contain an extra class referencing + // the same class name. + + MyTestDataDir testDataDir; + + testDataDir = MyTestDataDir(_("gotoslot_insertIntoCorrectClass_pointer")); + QTest::newRow("insertIntoCorrectClass_pointer") + << (QStringList() + << testDataDir.file(_("form.cpp")) + << testDataDir.file(_("form.h")) + << testDataDirWithoutProject.file(_("form.ui"))); // reuse + + testDataDir = MyTestDataDir(_("gotoslot_insertIntoCorrectClass_non-pointer")); + QTest::newRow("insertIntoCorrectClass_non-pointer") + << (QStringList() + << testDataDir.file(_("form.cpp")) + << testDataDir.file(_("form.h")) + << testDataDirWithoutProject.file(_("form.ui"))); // reuse + + testDataDir = MyTestDataDir(_("gotoslot_insertIntoCorrectClass_pointer_ns_using")); + QTest::newRow("insertIntoCorrectClass_pointer_ns_using") + << (QStringList() + << testDataDir.file(_("form.cpp")) + << testDataDir.file(_("form.h")) + << testDataDir.file(_("form.ui"))); +#endif } diff --git a/src/plugins/designer/qtcreatorintegration.cpp b/src/plugins/designer/qtcreatorintegration.cpp index 723c6f3191..ef40045b38 100644 --- a/src/plugins/designer/qtcreatorintegration.cpp +++ b/src/plugins/designer/qtcreatorintegration.cpp @@ -160,27 +160,26 @@ static bool inherits(const Overview &o, const Class *klass, const QString &baseC return false; } -// Check for a class name where haystack is a member class of an object. -// So, haystack can be shorter (can have some namespaces omitted because of a -// "using namespace" declaration, for example, comparing -// "foo::Ui::form", against "using namespace foo; Ui::form". - -static bool matchMemberClassName(const QString &needle, const QString &hayStack) +QString fullyQualifiedName(const LookupContext &context, const Name *name, Scope *scope) { - if (needle == hayStack) - return true; - if (!needle.endsWith(hayStack)) - return false; - // Check if there really is a separator "::" - const int separatorPos = needle.size() - hayStack.size() - 1; - return separatorPos > 1 && needle.at(separatorPos) == QLatin1Char(':'); + if (!name || !scope) + return QString(); + + const QList<LookupItem> items = context.lookup(name, scope); + if (items.isEmpty()) { // "ui_xxx.h" might not be generated and nothing is forward declared. + return Overview().prettyName(name); + } else { + Symbol *symbol = items.first().declaration(); + return Overview().prettyName(LookupContext::fullyQualifiedName(symbol)); + } + return QString(); } // Find class definition in namespace (that is, the outer class // containing a member of the desired class type) or inheriting the desired class // in case of forms using the Multiple Inheritance approach -static const Class *findClass(const Namespace *parentNameSpace, - const QString &className, QString *namespaceName) +static const Class *findClass(const Namespace *parentNameSpace, const LookupContext &context, + const QString &className, QString *namespaceName) { if (Designer::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << className; @@ -194,16 +193,22 @@ static const Class *findClass(const Namespace *parentNameSpace, // 1) we go through class members const unsigned classMemberCount = cl->memberCount(); for (unsigned j = 0; j < classMemberCount; ++j) - if (const Declaration *decl = cl->memberAt(j)->asDeclaration()) { + if (Declaration *decl = cl->memberAt(j)->asDeclaration()) { // we want to know if the class contains a member (so we look into // a declaration) of uiClassName type - const NamedType *nt = decl->type()->asNamedType(); + QString nameToMatch; + if (const NamedType *nt = decl->type()->asNamedType()) { + nameToMatch = fullyQualifiedName(context, nt->name(), + decl->enclosingScope()); // handle pointers to member variables - if (PointerType *pt = decl->type()->asPointerType()) - nt = pt->elementType()->asNamedType(); - - if (nt && matchMemberClassName(className, o.prettyName(nt->name()))) - return cl; + } else if (PointerType *pt = decl->type()->asPointerType()) { + if (NamedType *nt = pt->elementType()->asNamedType()) { + nameToMatch = fullyQualifiedName(context, nt->name(), + decl->enclosingScope()); + } + } + if (!nameToMatch.isEmpty() && className == nameToMatch) + return cl; } // decl // 2) does it inherit the desired class if (inherits(o, cl, className)) @@ -214,7 +219,7 @@ static const Class *findClass(const Namespace *parentNameSpace, QString tempNS = *namespaceName; tempNS += o.prettyName(ns->name()); tempNS += QLatin1String("::"); - if (const Class *cl = findClass(ns, className, &tempNS)) { + if (const Class *cl = findClass(ns, context, className, &tempNS)) { *namespaceName = tempNS; return cl; } @@ -345,7 +350,7 @@ static Document::Ptr addDefinition(const Snapshot &docTable, //! \todo use the InsertionPointLocator to insert at the correct place. // (we'll have to extend that class first to do definition insertions) - const QString contents = editable->textDocument()->contents(); + const QString contents = editable->textDocument()->plainText(); int column; editable->convertPosition(contents.length(), line, &column); editable->gotoLine(*line, column); @@ -445,14 +450,15 @@ static QString addParameterNames(const QString &functionSignature, const QString typedef QPair<const Class *, Document::Ptr> ClassDocumentPtrPair; static ClassDocumentPtrPair - findClassRecursively(const Snapshot &docTable, - const Document::Ptr &doc, const QString &className, + findClassRecursively(const LookupContext &context, const QString &className, unsigned maxIncludeDepth, QString *namespaceName) { + const Document::Ptr doc = context.thisDocument(); + const Snapshot docTable = context.snapshot(); if (Designer::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << doc->fileName() << className << maxIncludeDepth; // Check document - if (const Class *cl = findClass(doc->globalNamespace(), className, namespaceName)) + if (const Class *cl = findClass(doc->globalNamespace(), context, className, namespaceName)) return ClassDocumentPtrPair(cl, doc); if (maxIncludeDepth) { // Check the includes @@ -461,7 +467,9 @@ static ClassDocumentPtrPair const Snapshot::const_iterator it = docTable.find(include); if (it != docTable.end()) { const Document::Ptr includeDoc = it.value(); - const ClassDocumentPtrPair irc = findClassRecursively(docTable, it.value(), className, recursionMaxIncludeDepth, namespaceName); + LookupContext context(includeDoc, docTable); + const ClassDocumentPtrPair irc = findClassRecursively(context, className, + recursionMaxIncludeDepth, namespaceName); if (irc.first) return irc; } @@ -588,7 +596,8 @@ bool QtCreatorIntegration::navigateToSlot(const QString &objectName, Document::Ptr doc; foreach (const Document::Ptr &d, docMap) { - const ClassDocumentPtrPair cd = findClassRecursively(docTable, d, uiClass, 1u , &namespaceName); + LookupContext context(d, docTable); + const ClassDocumentPtrPair cd = findClassRecursively(context, uiClass, 1u , &namespaceName); if (cd.first) { cl = cd.first; doc = cd.second; diff --git a/src/plugins/fakevim/fakevim_test.cpp b/src/plugins/fakevim/fakevim_test.cpp index 06e732202b..1f0ea56a0f 100644 --- a/src/plugins/fakevim/fakevim_test.cpp +++ b/src/plugins/fakevim/fakevim_test.cpp @@ -2219,6 +2219,17 @@ void FakeVimPlugin::test_vim_substitute() COMMAND("'<,'>s/^/*", "abc" N "**def" N X "**ghi" N "jkl"); KEYS("u", "abc" N X "*def" N "*ghi" N "jkl"); KEYS("gv:s/^/+<CR>", "abc" N "+*def" N X "+*ghi" N "jkl"); + + // replace empty string + data.setText("abc"); + COMMAND("s//--/g", "--a--b--c"); + + // remove characters + data.setText("abc def"); + COMMAND("s/[abde]//g", "c f"); + COMMAND("undo | s/[bcef]//g", "a d"); + COMMAND("undo | s/\\w//g", " "); + COMMAND("undo | s/f\\|$/-/g", "abc de-"); } void FakeVimPlugin::test_vim_ex_yank() diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 0612b73fce..8d247ccda0 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -623,10 +623,22 @@ static bool substituteText(QString *text, QRegExp &pattern, const QString &repla { bool substituted = false; int pos = 0; + int right = -1; while (true) { pos = pattern.indexIn(*text, pos, QRegExp::CaretAtZero); if (pos == -1) break; + + // ensure that substitution is advancing towards end of line + if (right == text->size() - pos) { + ++pos; + if (pos == text->size()) + break; + continue; + } + + right = text->size() - pos; + substituted = true; QString matched = text->mid(pos, pattern.cap(0).size()); QString repl; @@ -652,7 +664,7 @@ static bool substituteText(QString *text, QRegExp &pattern, const QString &repla } } text->replace(pos, matched.size(), repl); - pos += qMax(1, repl.size()); + pos += (repl.isEmpty() && matched.isEmpty()) ? 1 : repl.size(); if (pos >= text->size() || !global) break; @@ -693,6 +705,33 @@ static void setClipboardData(const QString &content, RangeMode mode, clipboard->setMimeData(data, clipboardMode); } +static QByteArray toLocalEncoding(const QString &text) +{ + return HostOsInfo::isWindowsHost() ? QString(text).replace(_("\n"), _("\r\n")).toLocal8Bit() + : text.toLocal8Bit(); +} + +static QString fromLocalEncoding(const QByteArray &data) +{ + return HostOsInfo::isWindowsHost() ? QString::fromLocal8Bit(data).replace(_("\n"), _("\r\n")) + : QString::fromLocal8Bit(data); +} + +static QString getProcessOutput(const QString &command, const QString &input) +{ + QProcess proc; + proc.start(command); + proc.waitForStarted(); + proc.write(toLocalEncoding(input)); + proc.closeWriteChannel(); + + // FIXME: Process should be interruptable by user. + // Solution is to create a QObject for each process and emit finished state. + proc.waitForFinished(); + + return fromLocalEncoding(proc.readAllStandardOutput()); +} + static const QMap<QString, int> &vimKeyNames() { static QMap<QString, int> k; @@ -804,6 +843,11 @@ QString Range::toString() const .arg(rangemode); } +bool Range::isValid() const +{ + return beginPos >= 0 && endPos >= 0; +} + QDebug operator<<(QDebug ts, const Range &range) { return ts << '[' << range.beginPos << ',' << range.endPos << ']'; @@ -5038,9 +5082,6 @@ bool FakeVimHandler::Private::parseExCommmand(QString *line, ExCommand *cmd) if (line->isEmpty()) return false; - // remove leading colons and spaces - line->remove(QRegExp(_("^\\s*(:+\\s*)*"))); - // parse range first if (!parseLineRange(line, cmd)) return false; @@ -5093,6 +5134,15 @@ bool FakeVimHandler::Private::parseExCommmand(QString *line, ExCommand *cmd) bool FakeVimHandler::Private::parseLineRange(QString *line, ExCommand *cmd) { + // remove leading colons and spaces + line->remove(QRegExp(_("^\\s*(:+\\s*)*"))); + + // special case ':!...' (use invalid range) + if (line->startsWith(QLatin1Char('!'))) { + cmd->range = Range(); + return true; + } + // FIXME: that seems to be different for %w and %s if (line->startsWith(QLatin1Char('%'))) line->replace(0, 1, _("1,$")); @@ -5655,22 +5705,15 @@ bool FakeVimHandler::Private::handleExBangCommand(const ExCommand &cmd) // :! if (!cmd.cmd.isEmpty() || !cmd.hasBang) return false; - setCurrentRange(cmd.range); - int targetPosition = firstPositionInLine(lineForPosition(cmd.range.beginPos)); - QString command = QString(cmd.cmd.mid(1) + QLatin1Char(' ') + cmd.args).trimmed(); - QString text = selectText(cmd.range); - QProcess proc; - proc.start(command); - proc.waitForStarted(); - if (HostOsInfo::isWindowsHost()) - text.replace(_("\n"), _("\r\n")); - proc.write(text.toUtf8()); - proc.closeWriteChannel(); - proc.waitForFinished(); - QString result = QString::fromUtf8(proc.readAllStandardOutput()); - if (text.isEmpty()) { - emit q->extraInformationChanged(result); - } else { + bool replaceText = cmd.range.isValid(); + const QString command = QString(cmd.cmd.mid(1) + QLatin1Char(' ') + cmd.args).trimmed(); + const QString input = replaceText ? selectText(cmd.range) : QString(); + + const QString result = getProcessOutput(command, input); + + if (replaceText) { + setCurrentRange(cmd.range); + int targetPosition = firstPositionInLine(lineForPosition(cmd.range.beginPos)); beginEditBlock(); removeText(currentRange()); insertText(result); @@ -5679,8 +5722,11 @@ bool FakeVimHandler::Private::handleExBangCommand(const ExCommand &cmd) // :! leaveVisualMode(); //qDebug() << "FILTER: " << command; showMessage(MessageInfo, FakeVimHandler::tr("%n lines filtered.", 0, - text.count(QLatin1Char('\n')))); + input.count(QLatin1Char('\n')))); + } else if (!result.isEmpty()) { + emit q->extraInformationChanged(result); } + return true; } @@ -6478,10 +6524,19 @@ void FakeVimHandler::Private::scrollToLine(int line) EDITOR(setTextCursor(tc2)); EDITOR(ensureCursorVisible()); + int offset = 0; const QTextBlock block = document()->findBlockByLineNumber(line); - const QTextLine textLine = block.isValid() - ? block.layout()->lineAt(line - block.firstLineNumber()) : QTextLine(); - tc2.setPosition(block.position() + (textLine.isValid() ? textLine.textStart() : 0)); + if (block.isValid()) { + const int blockLineCount = block.layout()->lineCount(); + const int lineInBlock = line - block.firstLineNumber(); + if (0 <= lineInBlock && lineInBlock < blockLineCount) { + QTextLine textLine = block.layout()->lineAt(lineInBlock); + offset = textLine.textStart(); + } else { +// QTC_CHECK(false); + } + } + tc2.setPosition(block.position() + offset); EDITOR(setTextCursor(tc2)); EDITOR(ensureCursorVisible()); diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h index 3af38bd8b7..e6a1320b5a 100644 --- a/src/plugins/fakevim/fakevimhandler.h +++ b/src/plugins/fakevim/fakevimhandler.h @@ -52,6 +52,7 @@ struct Range Range(); Range(int b, int e, RangeMode m = RangeCharMode); QString toString() const; + bool isValid() const; int beginPos; int endPos; diff --git a/src/plugins/fakevim/fakevimoptions.ui b/src/plugins/fakevim/fakevimoptions.ui index 8974f2ae0c..6f5d21d6b1 100644 --- a/src/plugins/fakevim/fakevimoptions.ui +++ b/src/plugins/fakevim/fakevimoptions.ui @@ -92,7 +92,7 @@ <item row="6" column="1"> <widget class="QCheckBox" name="checkBoxPassControlKey"> <property name="toolTip"> - <string>Pass key sequences like Ctrl-S to Qt Creator core instead of interpreting them in FakeVim. This gives easier access to Qt Creator core functionality at the price of losing some features of FakeVim.</string> + <string>Passes key sequences like Ctrl-S to Qt Creator core instead of interpreting them in FakeVim. This gives easier access to Qt Creator core functionality at the price of losing some features of FakeVim.</string> </property> <property name="text"> <string>Pass control key</string> @@ -123,7 +123,7 @@ <item row="7" column="0"> <widget class="QCheckBox" name="checkBoxPassKeys"> <property name="toolTip"> - <string>Let Qt Creator handle some key presses in insert mode so that code can be properly completed and expanded.</string> + <string>Lets Qt Creator handle some key presses in insert mode so that code can be properly completed and expanded.</string> </property> <property name="text"> <string>Pass keys in insert mode</string> diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index f8e79162f2..b94bfe697c 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -1022,6 +1022,9 @@ FakeVimPluginPrivate::~FakeVimPluginPrivate() delete m_fakeVimUserCommandsPage; m_fakeVimUserCommandsPage = 0; + delete m_wordProvider; + m_wordProvider = 0; + theFakeVimSettings()->deleteLater(); } diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index fc9f05e23e..d12f2f2497 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -265,7 +265,7 @@ void GenericProject::refresh(RefreshOptions options) } part->cxxVersion = CppTools::ProjectPart::CXX11; // assume C++11 - part->defines += m_defines; + part->projectDefines += m_defines; // ### add _defines. diff --git a/src/plugins/git/branchdialog.cpp b/src/plugins/git/branchdialog.cpp index 9fadf16934..09e21ba2c8 100644 --- a/src/plugins/git/branchdialog.cpp +++ b/src/plugins/git/branchdialog.cpp @@ -38,11 +38,14 @@ #include "stashdialog.h" // Label helpers #include <utils/qtcassert.h> +#include <utils/execmenu.h> #include <vcsbase/vcsbaseoutputwindow.h> +#include <QAction> #include <QItemSelectionModel> #include <QMessageBox> #include <QList> +#include <QMenu> #include <QDebug> @@ -321,8 +324,18 @@ void BranchDialog::merge() const QString branch = m_model->fullName(idx, true); GitClient *client = GitPlugin::instance()->gitClient(); + bool allowFastForward = true; + if (client->isFastForwardMerge(m_repository, branch)) { + QMenu popup; + QAction *fastForward = popup.addAction(tr("Fast-Forward")); + popup.addAction(tr("No Fast-Forward")); + QAction *chosen = Utils::execMenuAtWidget(&popup, m_ui->mergeButton); + if (!chosen) + return; + allowFastForward = (chosen == fastForward); + } if (client->beginStashScope(m_repository, QLatin1String("merge"), AllowUnstashed)) - client->synchronousMerge(m_repository, branch); + client->synchronousMerge(m_repository, branch, allowFastForward); } void BranchDialog::rebase() diff --git a/src/plugins/git/gerrit/gerritpushdialog.cpp b/src/plugins/git/gerrit/gerritpushdialog.cpp index 466048cfa5..bfb06b38bd 100644 --- a/src/plugins/git/gerrit/gerritpushdialog.cpp +++ b/src/plugins/git/gerrit/gerritpushdialog.cpp @@ -33,8 +33,6 @@ #include "../gitplugin.h" #include "../gitclient.h" -#include <coreplugin/coreconstants.h> - #include <QDateTime> #include <QDir> #include <QRegExpValidator> @@ -46,7 +44,7 @@ class PushItemDelegate : public Git::Internal::IconItemDelegate { public: PushItemDelegate(Git::Internal::LogChangeWidget *widget) - : IconItemDelegate(widget, QLatin1String(Core::Constants::ICON_PLUS)) + : IconItemDelegate(widget, QLatin1String(":/git/images/arrowup.png")) { } diff --git a/src/plugins/git/git.qrc b/src/plugins/git/git.qrc index 3371b45cd8..15b93521a3 100644 --- a/src/plugins/git/git.qrc +++ b/src/plugins/git/git.qrc @@ -2,6 +2,7 @@ <qresource prefix="/git"> <file>images/git.png</file> <file>images/gitorious.png</file> + <file>images/arrowup.png</file> <file>Git.mimetypes.xml</file> </qresource> </RCC> diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 1b3d521559..6842489a82 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -85,6 +85,12 @@ static const char decorateOption[] = "--decorate"; namespace Git { namespace Internal { +// Suppress git diff warnings about "LF will be replaced by CRLF..." on Windows. +static inline unsigned diffExecutionFlags() +{ + return Utils::HostOsInfo::isWindowsHost() ? unsigned(VcsBase::VcsBasePlugin::SuppressStdErrInLogWindow) : 0u; +} + using VcsBase::VcsBasePlugin; class GitDiffSwitcher : public QObject @@ -391,6 +397,7 @@ void GitDiffHandler::collectFilesList(const QStringList &additionalArguments) QStringList arguments; arguments << QLatin1String("diff") << QLatin1String("--name-only") << additionalArguments; command->addJob(arguments, m_timeout); + command->addFlags(diffExecutionFlags()); command->execute(); } @@ -972,7 +979,7 @@ QString GitClient::findRepositoryForDirectory(const QString &dir) else if (directory.exists(QLatin1String(".git/config"))) return directory.absolutePath(); } - } while (directory.cdUp()); + } while (!directory.isRoot() && directory.cdUp()); return QString(); } @@ -1186,6 +1193,7 @@ void GitClient::diff(const QString &workingDirectory, command->addJob(arguments, timeout); } } + command->addFlags(diffExecutionFlags()); command->execute(); } if (newEditor) { @@ -1256,7 +1264,7 @@ void GitClient::diff(const QString &workingDirectory, const QString &fileName) if (!fileName.isEmpty()) cmdArgs << QLatin1String("--") << fileName; - executeGit(workingDirectory, cmdArgs, vcsEditor); + executeGit(workingDirectory, cmdArgs, vcsEditor, false, diffExecutionFlags()); } if (newEditor) { GitDiffSwitcher *switcher = new GitDiffSwitcher(newEditor, this); @@ -1315,7 +1323,7 @@ void GitClient::diffBranch(const QString &workingDirectory, << vcsEditor->configurationWidget()->arguments() << branchName; - executeGit(workingDirectory, cmdArgs, vcsEditor); + executeGit(workingDirectory, cmdArgs, vcsEditor, false, diffExecutionFlags()); } if (newEditor) { GitDiffSwitcher *switcher = new GitDiffSwitcher(newEditor, this); @@ -1537,7 +1545,7 @@ void GitClient::blame(const QString &workingDirectory, arguments << QLatin1String("--") << fileName; if (!revision.isEmpty()) arguments << revision; - executeGit(workingDirectory, arguments, editor, false, false, lineNumber); + executeGit(workingDirectory, arguments, editor, false, 0, lineNumber); } bool GitClient::synchronousCheckout(const QString &workingDirectory, @@ -1626,7 +1634,10 @@ void GitClient::reset(const QString &workingDirectory, const QString &argument, if (!commit.isEmpty()) arguments << commit; - executeGit(workingDirectory, arguments, 0, true, argument == QLatin1String("--hard")); + unsigned flags = 0; + if (argument == QLatin1String("--hard")) + flags |= VcsBasePlugin::ExpectRepoChanges; + executeGit(workingDirectory, arguments, 0, true, flags); } void GitClient::addFile(const QString &workingDirectory, const QString &fileName) @@ -2095,6 +2106,17 @@ bool GitClient::isRemoteCommit(const QString &workingDirectory, const QString &c return !outputText.isEmpty(); } +bool GitClient::isFastForwardMerge(const QString &workingDirectory, const QString &branch) +{ + QStringList arguments; + QByteArray outputText; + arguments << QLatin1String("merge-base") << QLatin1String(HEAD) << branch; + fullySynchronousGit(workingDirectory, arguments, &outputText, 0, + VcsBasePlugin::SuppressCommandLogging); + return commandOutputFromLocal8Bit(outputText).trimmed() + == synchronousTopRevision(workingDirectory); +} + // Format an entry in a one-liner for selection list using git log. QString GitClient::synchronousShortDescription(const QString &workingDirectory, const QString &revision, const QString &format) @@ -2489,14 +2511,13 @@ VcsBase::Command *GitClient::executeGit(const QString &workingDirectory, const QStringList &arguments, VcsBase::VcsBaseEditorWidget* editor, bool useOutputToWindow, - bool expectChanges, + unsigned additionalFlags, int editorLineNumber) { outputWindow()->appendCommand(workingDirectory, settings()->stringValue(GitSettings::binaryPathKey), arguments); VcsBase::Command *command = createCommand(workingDirectory, editor, useOutputToWindow, editorLineNumber); command->addJob(arguments, settings()->intValue(GitSettings::timeoutKey)); - if (expectChanges) - command->addFlags(VcsBasePlugin::ExpectRepoChanges); + command->addFlags(additionalFlags); command->execute(); return command; } @@ -2626,7 +2647,8 @@ void GitClient::updateSubmodulesIfNeeded(const QString &workingDirectory, bool p QStringList arguments; arguments << QLatin1String("submodule") << QLatin1String("update"); - VcsBase::Command *cmd = executeGit(workingDirectory, arguments, 0, true, true); + VcsBase::Command *cmd = executeGit(workingDirectory, arguments, 0, true, + VcsBasePlugin::ExpectRepoChanges); connect(cmd, SIGNAL(finished(bool,int,QVariant)), this, SLOT(finishSubmoduleUpdate())); } @@ -3474,12 +3496,15 @@ void GitClient::push(const QString &workingDirectory, const QStringList &pushArg executeGit(workingDirectory, arguments, 0, true); } -bool GitClient::synchronousMerge(const QString &workingDirectory, const QString &branch) +bool GitClient::synchronousMerge(const QString &workingDirectory, const QString &branch, + bool allowFastForward) { QString command = QLatin1String("merge"); - QStringList arguments; + QStringList arguments(command); - arguments << command << branch; + if (!allowFastForward) + arguments << QLatin1String("--no-ff"); + arguments << branch; return executeAndHandleConflicts(workingDirectory, arguments, command); } @@ -3578,7 +3603,8 @@ void GitClient::stashPop(const QString &workingDirectory, const QString &stash) arguments << QLatin1String("pop"); if (!stash.isEmpty()) arguments << stash; - VcsBase::Command *cmd = executeGit(workingDirectory, arguments, 0, true, true); + VcsBase::Command *cmd = executeGit(workingDirectory, arguments, 0, true, + VcsBasePlugin::ExpectRepoChanges); new ConflictHandler(cmd, workingDirectory); } diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index de86aea73b..69f11e9553 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -244,13 +244,15 @@ public: QStringList synchronousBranchesForCommit(const QString &workingDirectory, const QString &revision); bool isRemoteCommit(const QString &workingDirectory, const QString &commit); + bool isFastForwardMerge(const QString &workingDirectory, const QString &branch); bool cloneRepository(const QString &directory, const QByteArray &url); QString vcsGetRepositoryURL(const QString &directory); void fetch(const QString &workingDirectory, const QString &remote); bool synchronousPull(const QString &workingDirectory, bool rebase); void push(const QString &workingDirectory, const QStringList &pushArgs = QStringList()); - bool synchronousMerge(const QString &workingDirectory, const QString &branch); + bool synchronousMerge(const QString &workingDirectory, const QString &branch, + bool allowFastForward = true); bool canRebase(const QString &workingDirectory) const; void rebase(const QString &workingDirectory, const QString &baseBranch); bool synchronousRevert(const QString &workingDirectory, const QString &commit); @@ -374,7 +376,7 @@ private: const QStringList &arguments, VcsBase::VcsBaseEditorWidget* editor = 0, bool useOutputToWindow = false, - bool expectChanges = false, + unsigned additionalFlags = 0, int editorLineNumber = -1); // Fully synchronous git execution (QProcess-based). diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index f055c3f4b3..ae52a8a085 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -807,12 +807,11 @@ class ResetItemDelegate : public LogItemDelegate { public: ResetItemDelegate(LogChangeWidget *widget) : LogItemDelegate(widget) {} - void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const + void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const { - QStyleOptionViewItem o = option; if (index.row() < currentRow()) - o.font.setStrikeOut(true); - QStyledItemDelegate::paint(painter, o, index); + option->font.setStrikeOut(true); + LogItemDelegate::initStyleOption(option, index); } }; @@ -855,15 +854,13 @@ void GitPlugin::startRebase() const QString topLevel = state.topLevel(); if (topLevel.isEmpty() || !m_gitClient->canRebase(topLevel)) return; - if (!m_gitClient->beginStashScope(topLevel, QLatin1String("Rebase-i"))) - return; LogChangeDialog dialog(false, Core::ICore::mainWindow()); RebaseItemDelegate delegate(dialog.widget()); dialog.setWindowTitle(tr("Interactive Rebase")); - if (dialog.runDialog(topLevel, QString(), false)) + if (!dialog.runDialog(topLevel, QString(), false)) + return; + if (m_gitClient->beginStashScope(topLevel, QLatin1String("Rebase-i"))) m_gitClient->interactiveRebase(topLevel, dialog.commit(), false); - else - m_gitClient->endStashScope(topLevel); } void GitPlugin::startChangeRelatedAction() diff --git a/src/plugins/git/images/arrowup.png b/src/plugins/git/images/arrowup.png Binary files differnew file mode 100644 index 0000000000..5cdbc6ed9e --- /dev/null +++ b/src/plugins/git/images/arrowup.png diff --git a/src/plugins/git/logchangedialog.cpp b/src/plugins/git/logchangedialog.cpp index 6a316765b1..a52e1b7e9f 100644 --- a/src/plugins/git/logchangedialog.cpp +++ b/src/plugins/git/logchangedialog.cpp @@ -130,7 +130,8 @@ void LogChangeWidget::selectionChanged(const QItemSelection &selected, if (!m_hasCustomDelegate) return; const QModelIndexList previousIndexes = deselected.indexes(); - QTC_ASSERT(!previousIndexes.isEmpty(), return); + if (previousIndexes.isEmpty()) + return; const QModelIndex current = currentIndex(); int row = current.row(); int previousRow = previousIndexes.first().row(); diff --git a/src/plugins/git/logchangedialog.h b/src/plugins/git/logchangedialog.h index f95604d84c..9996c2f5bb 100644 --- a/src/plugins/git/logchangedialog.h +++ b/src/plugins/git/logchangedialog.h @@ -102,8 +102,6 @@ protected: LogItemDelegate(LogChangeWidget *widget); int currentRow() const; - virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const = 0; private: LogChangeWidget *m_widget; diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index 33113f689e..68b75b8c8c 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -302,8 +302,7 @@ bool HelpPlugin::initialize(const QStringList &arguments, QString *error) if (ActionContainer *windowMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW)) { // reuse EditorManager constants to avoid a second pair of menu actions // Goto Previous In History Action - action = new QAction(QApplication::translate("EditorManager", - "Next Open Document in History"), this); + action = new QAction(this); Command *ctrlTab = ActionManager::registerAction(action, Core::Constants::GOTOPREVINHISTORY, modecontext); windowMenu->addAction(ctrlTab, Core::Constants::G_WINDOW_NAVIGATE); @@ -311,8 +310,7 @@ bool HelpPlugin::initialize(const QStringList &arguments, QString *error) SLOT(gotoPreviousPage())); // Goto Next In History Action - action = new QAction(QApplication::translate("EditorManager", - "Previous Open Document in History"), this); + action = new QAction(this); Command *ctrlShiftTab = ActionManager::registerAction(action, Core::Constants::GOTONEXTINHISTORY, modecontext); windowMenu->addAction(ctrlShiftTab, Core::Constants::G_WINDOW_NAVIGATE); diff --git a/src/plugins/ios/images/iossettings.png b/src/plugins/ios/images/iossettings.png Binary files differnew file mode 100755 index 0000000000..307d525188 --- /dev/null +++ b/src/plugins/ios/images/iossettings.png diff --git a/src/plugins/ios/ios.qrc b/src/plugins/ios/ios.qrc index 81314b84cd..cf041359ad 100644 --- a/src/plugins/ios/ios.qrc +++ b/src/plugins/ios/ios.qrc @@ -1,5 +1,5 @@ <RCC> <qresource prefix="/ios"> - <file>images/QtIos.png</file> + <file>images/iossettings.png</file> </qresource> </RCC> diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index 8e87c78419..34c6f02b1b 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -113,7 +113,8 @@ void IosConfigurations::updateAutomaticKitList() iter.next(); const Platform &p = iter.value(); if (p.compilerPath == toolchain->compilerCommand() - && p.backendFlags == toolchain->platformCodeGenFlags()) { + && p.backendFlags == toolchain->platformCodeGenFlags() + && !platformToolchainMap.contains(p.name)) { platformToolchainMap[p.name] = toolchain; found = true; } @@ -251,7 +252,7 @@ void IosConfigurations::updateAutomaticKitList() qDebug() << "skipping existing kit with deviceKind " << deviceKind.toString(); continue; } - if (!k->isAutoDetected()) // use also used set kits? + if (!k->isAutoDetected()) continue; existingKits << k; kitMatched << false; @@ -285,15 +286,20 @@ void IosConfigurations::updateAutomaticKitList() QList<BaseQtVersion *> qtVersions = qtVersionsForArch.value(arch); foreach (BaseQtVersion *qt, qtVersions) { + Kit *kitAtt = 0; bool kitExists = false; for (int i = 0; i < existingKits.size(); ++i) { Kit *k = existingKits.at(i); if (DeviceTypeKitInformation::deviceTypeId(k) == pDeviceType && ToolChainKitInformation::toolChain(k) == pToolchain - && SysRootKitInformation::sysRoot(k) == p.sdkPath && QtKitInformation::qtVersion(k) == qt) { + QTC_CHECK(!kitMatched.value(i, true)); + // as we generate only two kits per qt (one for device and one for simulator) + // we do not compare the sdk (thus automatically upgrading it in place if a + // new Xcode is used). Change? kitExists = true; + kitAtt = k; if (debugProbe) qDebug() << "found existing kit " << k->displayName() << " for " << p.name << "," << qt->displayName(); @@ -302,74 +308,65 @@ void IosConfigurations::updateAutomaticKitList() break; } } - if (kitExists) - continue; - if (debugProbe) - qDebug() << "setting up new kit for " << p.name; - Kit *newKit = new Kit; - newKit->setAutoDetected(true); - QString baseDisplayName = tr("%1 %2").arg(p.name, qt->displayName()); - QString displayName = baseDisplayName; - for (int iVers = 1; iVers < 100; ++iVers) { - bool unique = true; - foreach (const Kit *k, existingKits) { - if (k->displayName() == displayName) { - unique = false; - break; + if (kitExists) { + kitAtt->blockNotification(); + } else { + if (debugProbe) + qDebug() << "setting up new kit for " << p.name; + kitAtt = new Kit; + kitAtt->setAutoDetected(true); + QString baseDisplayName = tr("%1 %2").arg(p.name, qt->displayName()); + QString displayName = baseDisplayName; + for (int iVers = 1; iVers < 100; ++iVers) { + bool unique = true; + foreach (const Kit *k, existingKits) { + if (k->displayName() == displayName) { + unique = false; + break; + } } + if (unique) break; + displayName = baseDisplayName + QLatin1String("-") + QString::number(iVers); } - if (unique) break; - displayName = baseDisplayName + QLatin1String("-") + QString::number(iVers); + kitAtt->setDisplayName(displayName); } - newKit->setDisplayName(displayName); - newKit->setIconPath(Utils::FileName::fromString( + kitAtt->setIconPath(Utils::FileName::fromString( QLatin1String(Constants::IOS_SETTINGS_CATEGORY_ICON))); - DeviceTypeKitInformation::setDeviceTypeId(newKit, pDeviceType); - ToolChainKitInformation::setToolChain(newKit, pToolchain); - QtKitInformation::setQtVersion(newKit, qt); - //DeviceKitInformation::setDevice(newKit, device); - if (!debuggerId.isValid()) - Debugger::DebuggerKitInformation::setDebugger(newKit, + DeviceTypeKitInformation::setDeviceTypeId(kitAtt, pDeviceType); + ToolChainKitInformation::setToolChain(kitAtt, pToolchain); + QtKitInformation::setQtVersion(kitAtt, qt); + if ((!Debugger::DebuggerKitInformation::debugger(kitAtt) + || !Debugger::DebuggerKitInformation::debugger(kitAtt)->isValid() + || Debugger::DebuggerKitInformation::debugger(kitAtt)->engineType() != Debugger::LldbEngineType) + && debuggerId.isValid()) + Debugger::DebuggerKitInformation::setDebugger(kitAtt, debuggerId); - newKit->setMutable(DeviceKitInformation::id(), true); - newKit->setSticky(QtKitInformation::id(), true); - newKit->setSticky(ToolChainKitInformation::id(), true); - newKit->setSticky(DeviceTypeKitInformation::id(), true); - newKit->setSticky(SysRootKitInformation::id(), true); + kitAtt->setMutable(DeviceKitInformation::id(), true); + kitAtt->setSticky(QtKitInformation::id(), true); + kitAtt->setSticky(ToolChainKitInformation::id(), true); + kitAtt->setSticky(DeviceTypeKitInformation::id(), true); + kitAtt->setSticky(SysRootKitInformation::id(), true); + kitAtt->setSticky(Debugger::DebuggerKitInformation::id(), false); - SysRootKitInformation::setSysRoot(newKit, p.sdkPath); + SysRootKitInformation::setSysRoot(kitAtt, p.sdkPath); // QmakeProjectManager::QmakeKitInformation::setMkspec(newKit, // Utils::FileName::fromString(QLatin1String("macx-ios-clang"))); - KitManager::registerKit(newKit); - existingKits << newKit; + if (kitExists) { + kitAtt->unblockNotification(); + } else { + KitManager::registerKit(kitAtt); + existingKits << kitAtt; + } } } } for (int i = 0; i < kitMatched.size(); ++i) { // deleting extra (old) kits - if (!kitMatched.at(i) && !existingKits.at(i)->isValid()) { + if (!kitMatched.at(i)) { qDebug() << "deleting kit " << existingKits.at(i)->displayName(); KitManager::deregisterKit(existingKits.at(i)); } - // fix old kits - if (kitMatched.at(i)) { - Kit *kit = existingKits.at(i); - kit->blockNotification(); - const Debugger::DebuggerItem *debugger = Debugger::DebuggerKitInformation::debugger(kit); - if ((!debugger || !debugger->isValid()) && debuggerId.isValid()) - Debugger::DebuggerKitInformation::setDebugger(kit, debuggerId); - if (!kit->isMutable(DeviceKitInformation::id())) { - kit->setMutable(DeviceKitInformation::id(), true); - kit->setSticky(QtKitInformation::id(), true); - kit->setSticky(ToolChainKitInformation::id(), true); - kit->setSticky(DeviceTypeKitInformation::id(), true); - kit->setSticky(SysRootKitInformation::id(), true); - } - if (kit->isSticky(Debugger::DebuggerKitInformation::id())) - kit->setSticky(Debugger::DebuggerKitInformation::id(), false); - kit->unblockNotification(); - } } } diff --git a/src/plugins/ios/iosconstants.h b/src/plugins/ios/iosconstants.h index 6eb17c67f7..f4df71a091 100644 --- a/src/plugins/ios/iosconstants.h +++ b/src/plugins/ios/iosconstants.h @@ -48,7 +48,7 @@ namespace Constants { const char IOS_SETTINGS_ID[] = "ZZ.Ios Configurations"; const char IOS_SETTINGS_CATEGORY[] = "XA.Ios"; const char IOS_SETTINGS_TR_CATEGORY[] = QT_TRANSLATE_NOOP("Ios", "iOS"); -const char IOS_SETTINGS_CATEGORY_ICON[] = ":/ios/images/QtIos.png"; +const char IOS_SETTINGS_CATEGORY_ICON[] = ":/ios/images/iossettings.png"; const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios"; const char IOS_DEVICE_TYPE[] = "Ios.Device.Type"; diff --git a/src/plugins/ios/iosdebugsupport.cpp b/src/plugins/ios/iosdebugsupport.cpp index 32d69447af..44edcb276b 100644 --- a/src/plugins/ios/iosdebugsupport.cpp +++ b/src/plugins/ios/iosdebugsupport.cpp @@ -162,7 +162,9 @@ void IosDebugSupport::handleGotInferiorPid(Q_PID pid) { if (pid > 0) { //m_runControl->engine()->notifyInferiorPid(pid); +#ifndef Q_OS_WIN // Q_PID might be 64 bit pointer... m_runControl->engine()->notifyEngineRemoteSetupDone(int(pid), m_qmlPort); +#endif } else { m_runControl->engine()->notifyEngineRemoteSetupFailed( tr("Got an invalid process id.")); diff --git a/src/plugins/ios/iosdeploystep.cpp b/src/plugins/ios/iosdeploystep.cpp index 35a8d7bc6d..37baafeea6 100644 --- a/src/plugins/ios/iosdeploystep.cpp +++ b/src/plugins/ios/iosdeploystep.cpp @@ -75,6 +75,7 @@ IosDeployStep::~IosDeployStep() { } void IosDeployStep::ctor() { + m_toolHandler = 0; m_transferStatus = NoTransfer; m_device = ProjectExplorer::DeviceKitInformation::device(target()->kit()); const QString devName = m_device.isNull() ? IosDevice::name() : m_device->displayName(); @@ -103,23 +104,24 @@ void IosDeployStep::run(QFutureInterface<bool> &fi) ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT); m_futureInterface.reportResult(!iossimulator().isNull()); cleanup(); - m_futureInterface.reportFinished(); + emit finished(); return; } m_transferStatus = TransferInProgress; - IosToolHandler *toolHandler = new IosToolHandler(IosToolHandler::IosDeviceType, this); + QTC_CHECK(m_toolHandler == 0); + m_toolHandler = new IosToolHandler(IosToolHandler::IosDeviceType, this); m_futureInterface.setProgressRange(0, 200); m_futureInterface.setProgressValueAndText(0, QLatin1String("Transferring application")); m_futureInterface.reportStarted(); - connect(toolHandler, SIGNAL(isTransferringApp(Ios::IosToolHandler*,QString,QString,int,int,QString)), + connect(m_toolHandler, SIGNAL(isTransferringApp(Ios::IosToolHandler*,QString,QString,int,int,QString)), SLOT(handleIsTransferringApp(Ios::IosToolHandler*,QString,QString,int,int,QString))); - connect(toolHandler, SIGNAL(didTransferApp(Ios::IosToolHandler*,QString,QString,Ios::IosToolHandler::OpStatus)), + connect(m_toolHandler, SIGNAL(didTransferApp(Ios::IosToolHandler*,QString,QString,Ios::IosToolHandler::OpStatus)), SLOT(handleDidTransferApp(Ios::IosToolHandler*,QString,QString,Ios::IosToolHandler::OpStatus))); - connect(toolHandler, SIGNAL(finished(Ios::IosToolHandler*)), + connect(m_toolHandler, SIGNAL(finished(Ios::IosToolHandler*)), SLOT(handleFinished(Ios::IosToolHandler*))); - connect(toolHandler, SIGNAL(errorMsg(Ios::IosToolHandler*,QString)), + connect(m_toolHandler, SIGNAL(errorMsg(Ios::IosToolHandler*,QString)), SLOT(handleErrorMsg(Ios::IosToolHandler*,QString))); - toolHandler->requestTransferApp(appBundle(), deviceId()); + m_toolHandler->requestTransferApp(appBundle(), deviceId()); } void IosDeployStep::cancel() @@ -179,7 +181,7 @@ void IosDeployStep::handleFinished(IosToolHandler *handler) cleanup(); handler->deleteLater(); // move it when result is reported? (would need care to avoid problems with concurrent runs) - m_futureInterface.reportFinished(); + emit finished(); } void IosDeployStep::handleErrorMsg(IosToolHandler *handler, const QString &msg) diff --git a/src/plugins/ios/iosdeploystep.h b/src/plugins/ios/iosdeploystep.h index e74a5c0bbb..05485b0b66 100644 --- a/src/plugins/ios/iosdeploystep.h +++ b/src/plugins/ios/iosdeploystep.h @@ -51,26 +51,6 @@ namespace Internal { class IosDeviceConfigListModel; class IosPackageCreationStep; -class DeployItem -{ -public: - DeployItem(const QString &_localFileName, - unsigned int _localTimeStamp, - const QString &_remoteFileName, - bool _needsStrip) - : localFileName(_localFileName), - remoteFileName(_remoteFileName), - localTimeStamp(_localTimeStamp), - remoteTimeStamp(0), - needsStrip(_needsStrip) - {} - QString localFileName; - QString remoteFileName; - unsigned int localTimeStamp; - unsigned int remoteTimeStamp; - bool needsStrip; -}; - class IosDeployStep : public ProjectExplorer::BuildStep { Q_OBJECT diff --git a/src/plugins/ios/iosdevice.cpp b/src/plugins/ios/iosdevice.cpp index b0d552345c..58cf894b96 100644 --- a/src/plugins/ios/iosdevice.cpp +++ b/src/plugins/ios/iosdevice.cpp @@ -46,6 +46,8 @@ #include <CoreFoundation/CoreFoundation.h> #endif +#include <exception> + using namespace ProjectExplorer; static bool debugDeviceDetection = false; @@ -85,7 +87,7 @@ IosDevice::IosDevice() Constants::IOS_DEVICE_ID) { setDisplayName(IosDevice::name()); - setDeviceState(DeviceStateUnknown); + setDeviceState(DeviceDisconnected); } IosDevice::IosDevice(const IosDevice &other) @@ -99,7 +101,7 @@ IosDevice::IosDevice(const QString &uid) Core::Id(Constants::IOS_DEVICE_ID).withSuffix(uid)) { setDisplayName(IosDevice::name()); - setDeviceState(DeviceStateUnknown); + setDeviceState(DeviceDisconnected); } @@ -364,62 +366,80 @@ io_iterator_t gRemovedIter; extern "C" { void deviceConnectedCallback(void *refCon, io_iterator_t iterator) { - kern_return_t kr; - io_service_t usbDevice; - (void) refCon; - - while ((usbDevice = IOIteratorNext(iterator))) { - io_name_t deviceName; - - // Get the USB device's name. - kr = IORegistryEntryGetName(usbDevice, deviceName); - QString name; - if (KERN_SUCCESS == kr) - name = QString::fromLocal8Bit(deviceName); - if (debugDeviceDetection) - qDebug() << "ios device " << name << " in deviceAddedCallback"; - - CFStringRef cfUid = static_cast<CFStringRef>(IORegistryEntryCreateCFProperty( - usbDevice, - CFSTR(kUSBSerialNumberString), - kCFAllocatorDefault, 0)); - QString uid = CFStringRef2QString(cfUid); - CFRelease(cfUid); - IosDeviceManager::instance()->deviceConnected(uid, name); - - // Done with this USB device; release the reference added by IOIteratorNext - kr = IOObjectRelease(usbDevice); - } -} - -void deviceDisconnectedCallback(void *refCon, io_iterator_t iterator) -{ - kern_return_t kr; - io_service_t usbDevice; - (void) refCon; - - while ((usbDevice = IOIteratorNext(iterator))) { - io_name_t deviceName; - - // Get the USB device's name. - kr = IORegistryEntryGetName(usbDevice, deviceName); - if (KERN_SUCCESS != kr) - deviceName[0] = '\0'; - if (debugDeviceDetection) - qDebug() << "ios device " << deviceName << " in deviceDisconnectedCallback"; + try { + kern_return_t kr; + io_service_t usbDevice; + (void) refCon; + + while ((usbDevice = IOIteratorNext(iterator))) { + io_name_t deviceName; + + // Get the USB device's name. + kr = IORegistryEntryGetName(usbDevice, deviceName); + QString name; + if (KERN_SUCCESS == kr) + name = QString::fromLocal8Bit(deviceName); + if (debugDeviceDetection) + qDebug() << "ios device " << name << " in deviceAddedCallback"; - { CFStringRef cfUid = static_cast<CFStringRef>(IORegistryEntryCreateCFProperty( usbDevice, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0)); QString uid = CFStringRef2QString(cfUid); CFRelease(cfUid); - IosDeviceManager::instance()->deviceDisconnected(uid); + IosDeviceManager::instance()->deviceConnected(uid, name); + + // Done with this USB device; release the reference added by IOIteratorNext + kr = IOObjectRelease(usbDevice); } + } + catch (std::exception &e) { + qDebug() << "Exception " << e.what() << " in iosdevice.cpp deviceConnectedCallback"; + } + catch (...) { + qDebug() << "Exception in iosdevice.cpp deviceConnectedCallback"; + throw; + } +} + +void deviceDisconnectedCallback(void *refCon, io_iterator_t iterator) +{ + try { + kern_return_t kr; + io_service_t usbDevice; + (void) refCon; + + while ((usbDevice = IOIteratorNext(iterator))) { + io_name_t deviceName; + + // Get the USB device's name. + kr = IORegistryEntryGetName(usbDevice, deviceName); + if (KERN_SUCCESS != kr) + deviceName[0] = '\0'; + if (debugDeviceDetection) + qDebug() << "ios device " << deviceName << " in deviceDisconnectedCallback"; + + { + CFStringRef cfUid = static_cast<CFStringRef>(IORegistryEntryCreateCFProperty( + usbDevice, + CFSTR(kUSBSerialNumberString), + kCFAllocatorDefault, 0)); + QString uid = CFStringRef2QString(cfUid); + CFRelease(cfUid); + IosDeviceManager::instance()->deviceDisconnected(uid); + } - // Done with this USB device; release the reference added by IOIteratorNext - kr = IOObjectRelease(usbDevice); + // Done with this USB device; release the reference added by IOIteratorNext + kr = IOObjectRelease(usbDevice); + } + } + catch (std::exception &e) { + qDebug() << "Exception " << e.what() << " in iosdevice.cpp deviceDisconnectedCallback"; + } + catch (...) { + qDebug() << "Exception in iosdevice.cpp deviceDisconnectedCallback"; + throw; } } diff --git a/src/plugins/ios/iossimulator.cpp b/src/plugins/ios/iossimulator.cpp index 3d79b9fbae..711d3f7e30 100644 --- a/src/plugins/ios/iossimulator.cpp +++ b/src/plugins/ios/iossimulator.cpp @@ -49,6 +49,7 @@ IosSimulator::IosSimulator(Core::Id id, Utils::FileName simulatorPath) m_simulatorPath(simulatorPath) { setDisplayName(QCoreApplication::translate("Ios::Internal::IosSimulator", "iOS Simulator")); + setDeviceState(DeviceReadyToUse); } IosSimulator::IosSimulator() @@ -65,6 +66,7 @@ IosSimulator::IosSimulator(const IosSimulator &other) : IDevice(other) { setDisplayName(QCoreApplication::translate("Ios::Internal::IosSimulator", "iOS Simulator")); + setDeviceState(DeviceReadyToUse); } diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp index 5a6eaf6491..cc921ae41e 100644 --- a/src/plugins/ios/iostoolhandler.cpp +++ b/src/plugins/ios/iostoolhandler.cpp @@ -42,6 +42,8 @@ #include <QList> #include <QScopedArrayPointer> #include <QProcessEnvironment> +#include <QFileInfo> +#include <QTimer> #include <string.h> #include <errno.h> @@ -129,7 +131,7 @@ public: virtual void requestDeviceInfo(const QString &deviceId, int timeout = 1000) = 0; bool isRunning(); void start(const QString &exe, const QStringList &args); - void stop(); + void stop(int errorCode); // signals void isTransferringApp(const QString &bundlePath, const QString &deviceId, int progress, @@ -148,12 +150,14 @@ public: void subprocessError(QProcess::ProcessError error); void subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus); void subprocessHasData(); + void killProcess(); virtual bool expectsFileDescriptor() = 0; protected: void processXml(); IosToolHandler *q; QProcess process; + QTimer killTimer; QXmlStreamReader outputParser; QString deviceId; QString bundlePath; @@ -199,16 +203,28 @@ IosToolHandlerPrivate::IosToolHandlerPrivate(IosToolHandler::DeviceType devType, q(q), state(NonStarted), devType(devType), iBegin(0), iEnd(0), gdbSocket(-1) { + killTimer.setSingleShot(true); QProcessEnvironment env(QProcessEnvironment::systemEnvironment()); foreach (const QString &k, env.keys()) if (k.startsWith(QLatin1String("DYLD_"))) env.remove(k); + QStringList frameworkPaths; + QString xcPath = IosConfigurations::developerPath().appendPath(QLatin1String("../OtherFrameworks")).toFileInfo().canonicalFilePath(); + if (!xcPath.isEmpty()) + frameworkPaths << xcPath; + frameworkPaths << QLatin1String("/System/Library/Frameworks") + << QLatin1String("/System/Library/PrivateFrameworks"); + env.insert(QLatin1String("DYLD_FALLBACK_FRAMEWORK_PATH"), frameworkPaths.join(QLatin1String(":"))); + if (debugToolHandler) + qDebug() << "IosToolHandler runEnv:" << env.toStringList(); process.setProcessEnvironment(env); QObject::connect(&process, SIGNAL(readyReadStandardOutput()), q, SLOT(subprocessHasData())); QObject::connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), q, SLOT(subprocessFinished(int,QProcess::ExitStatus))); QObject::connect(&process, SIGNAL(error(QProcess::ProcessError)), q, SLOT(subprocessError(QProcess::ProcessError))); + QObject::connect(&killTimer, SIGNAL(timeout()), + q, SLOT(killProcess())); } bool IosToolHandlerPrivate::isRunning() @@ -226,19 +242,41 @@ void IosToolHandlerPrivate::start(const QString &exe, const QStringList &args) state = StartedInferior; } -void IosToolHandlerPrivate::stop() +void IosToolHandlerPrivate::stop(int errorCode) { if (debugToolHandler) qDebug() << "IosToolHandlerPrivate::stop"; - if (process.state() != QProcess::NotRunning) { - process.close(); - process.kill(); - if (debugToolHandler) - qDebug() << "killing"; + State oldState = state; + state = Stopped; + switch (oldState) { + case NonStarted: + qDebug() << "IosToolHandler::stop() when state was NonStarted"; + // pass + case Starting: + switch (op){ + case OpNone: + qDebug() << "IosToolHandler::stop() when op was OpNone"; + break; + case OpAppTransfer: + didTransferApp(bundlePath, deviceId, IosToolHandler::Failure); + break; + case OpAppRun: + didStartApp(bundlePath, deviceId, IosToolHandler::Failure); + break; + case OpDeviceInfo: + break; + } + // pass + case StartedInferior: + case XmlEndProcessed: + toolExited(errorCode); + break; + case Stopped: + return; } - if (state != Stopped) { - state = Stopped; - emit q->finished(q); + if (process.state() != QProcess::NotRunning) { + process.terminate(); + killTimer.start(1500); } } @@ -296,67 +334,23 @@ void IosToolHandlerPrivate::toolExited(int code) void IosToolHandlerPrivate::subprocessError(QProcess::ProcessError error) { - switch (state) { - case NonStarted: - qDebug() << "subprocessError() when state was NonStarted"; - // pass - case Starting: - switch (op){ - case OpNone: - qDebug() << "subprocessError() when op is OpNone"; - break; - case OpAppTransfer: - didTransferApp(bundlePath, deviceId, IosToolHandler::Failure); - break; - case OpAppRun: - didStartApp(bundlePath, deviceId, IosToolHandler::Failure); - break; - case OpDeviceInfo: - break; - } - // pass - case StartedInferior: - errorMsg(IosToolHandler::tr("Subprocess Error %1").arg(error)); - toolExited(-1); - break; - case XmlEndProcessed: - case Stopped: - qDebug() << "IosToolHandler, subprocessError() in an already stopped process"; + if (state != Stopped) + errorMsg(IosToolHandler::tr("iOS tool Error %1").arg(error)); + stop(-1); + if (error == QProcess::FailedToStart) { + if (debugToolHandler) + qDebug() << "IosToolHandler::finished(" << this << ")"; + emit q->finished(q); } } void IosToolHandlerPrivate::subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus) { - // process potentially pending data - subprocessHasData(); - switch (state) { - case NonStarted: - qDebug() << "subprocessFinished() when state was NonStarted"; - // pass - case Starting: - switch (op){ - case OpNone: - qDebug() << "subprocessFinished() when op was OpNone"; - break; - case OpAppTransfer: - didTransferApp(bundlePath, deviceId, IosToolHandler::Failure); - break; - case OpAppRun: - didStartApp(bundlePath, deviceId, IosToolHandler::Failure); - break; - case OpDeviceInfo: - break; - } - // pass - case StartedInferior: - case XmlEndProcessed: - toolExited((exitStatus == QProcess::CrashExit && exitCode == 0) ? -1 : exitCode); - break; - case Stopped: - if (debugToolHandler) - qDebug() << "IosToolHandler, subprocessFinished() in an already stopped process (normal)"; - break; - } + stop((exitStatus == QProcess::NormalExit) ? exitCode : -1 ); + if (debugToolHandler) + qDebug() << "IosToolHandler::finished(" << this << ")"; + killTimer.stop(); + emit q->finished(q); } void IosToolHandlerPrivate::processXml() @@ -469,7 +463,8 @@ void IosToolHandlerPrivate::processXml() break; case ParserState::QueryResult: state = XmlEndProcessed; - break; + stop(0); + return; case ParserState::AppOutput: break; case ParserState::AppStarted: @@ -523,7 +518,7 @@ void IosToolHandlerPrivate::processXml() if (outputParser.hasError() && outputParser.error() != QXmlStreamReader::PrematureEndOfDocumentError) { qDebug() << "error parsing iosTool output:" << outputParser.errorString(); - stop(); + stop(-1); } } @@ -544,7 +539,7 @@ void IosToolHandlerPrivate::subprocessHasData() while (true) { qint64 rRead = process.read(buf, sizeof(buf)); if (rRead == -1) { - stop(); + stop(-1); return; } if (rRead == 0) @@ -556,7 +551,7 @@ void IosToolHandlerPrivate::subprocessHasData() } } case XmlEndProcessed: - stop(); + stop(0); return; case Stopped: return; @@ -707,6 +702,12 @@ void IosSimulatorToolHandlerPrivate::addDeviceArguments(QStringList &args) const } } +void IosToolHandlerPrivate::killProcess() +{ + if (process.state() != QProcess::NotRunning) + process.kill(); +} + } // namespace Internal QString IosToolHandler::iosDeviceToolPath() @@ -737,7 +738,7 @@ IosToolHandler::~IosToolHandler() void IosToolHandler::stop() { - d->stop(); + d->stop(-1); } void IosToolHandler::requestTransferApp(const QString &bundlePath, const QString &deviceId, @@ -777,4 +778,9 @@ void IosToolHandler::subprocessHasData() d->subprocessHasData(); } +void IosToolHandler::killProcess() +{ + d->killProcess(); +} + } // namespace Ios diff --git a/src/plugins/ios/iostoolhandler.h b/src/plugins/ios/iostoolhandler.h index 11c4a56e75..de8e53c484 100644 --- a/src/plugins/ios/iostoolhandler.h +++ b/src/plugins/ios/iostoolhandler.h @@ -99,6 +99,7 @@ private slots: void subprocessError(QProcess::ProcessError error); void subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus); void subprocessHasData(); + void killProcess(); private: friend class Ios::Internal::IosToolHandlerPrivate; Ios::Internal::IosToolHandlerPrivate *d; diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 6c9f4fc701..e04c1006d2 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -94,10 +94,3 @@ SUBDIRS += debugger/dumper.pro linux-* { SUBDIRS += debugger/ptracepreload.pro } - -include (debugger/lldblib/guest/qtcreator-lldb.pri) - -plugin_pythoneditor.subdir = pythoneditor -plugin_pythoneditor.depends = plugin_coreplugin -plugin_pythoneditor.depends += plugin_cpptools -plugin_pythoneditor.depends += plugin_texteditor diff --git a/src/plugins/projectexplorer/kitchooser.cpp b/src/plugins/projectexplorer/kitchooser.cpp index d494f29972..76f0fafed6 100644 --- a/src/plugins/projectexplorer/kitchooser.cpp +++ b/src/plugins/projectexplorer/kitchooser.cpp @@ -100,10 +100,11 @@ void KitChooser::populate() m_chooser->setItemData(m_chooser->count() - 1, kitToolTip(kit), Qt::ToolTipRole); } } - m_chooser->setEnabled(m_chooser->count() > 1); + const int n = m_chooser->count(); const int index = Core::ICore::settings()->value(QLatin1String(lastKitKey)).toInt(); - m_chooser->setCurrentIndex(qMin(index, m_chooser->count())); + m_chooser->setCurrentIndex(0 <= index && index < n ? index : -1); + m_chooser->setEnabled(n > 1); } Kit *KitChooser::currentKit() const diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp index 23edc2d2ab..87c6caf320 100644 --- a/src/plugins/projectexplorer/kitinformation.cpp +++ b/src/plugins/projectexplorer/kitinformation.cpp @@ -357,11 +357,10 @@ QList<Task> DeviceKitInformation::validate(const Kit *k) const void DeviceKitInformation::fix(Kit *k) { IDevice::ConstPtr dev = DeviceKitInformation::device(k); - if (!dev.isNull() && dev->type() == DeviceTypeKitInformation::deviceTypeId(k)) - return; - - qWarning("Device is no longer known, removing from kit \"%s\".", qPrintable(k->displayName())); - setDeviceId(k, Core::Id()); + if (!dev.isNull() && dev->type() != DeviceTypeKitInformation::deviceTypeId(k)) { + qWarning("Device is no longer known, removing from kit \"%s\".", qPrintable(k->displayName())); + setDeviceId(k, Core::Id()); + } } void DeviceKitInformation::setup(Kit *k) diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 25270eb353..7a3e31565e 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -59,21 +59,42 @@ #include <QAction> #include <QItemDelegate> +#if QT_VERSION >= 0x050100 +#include <QGuiApplication> +#endif + static QIcon createCenteredIcon(const QIcon &icon, const QIcon &overlay) { QPixmap targetPixmap; - targetPixmap = QPixmap(Core::Constants::TARGET_ICON_SIZE, Core::Constants::TARGET_ICON_SIZE); + qreal appDevicePixelRatio = 1.0; +#if QT_VERSION >= 0x050100 + appDevicePixelRatio = qApp->devicePixelRatio(); +#endif + int deviceSpaceIconSize = Core::Constants::TARGET_ICON_SIZE * appDevicePixelRatio; + targetPixmap = QPixmap(deviceSpaceIconSize, deviceSpaceIconSize); +#if QT_VERSION >= 0x050100 + targetPixmap.setDevicePixelRatio(appDevicePixelRatio); +#endif targetPixmap.fill(Qt::transparent); - QPainter painter(&targetPixmap); - - QPixmap pixmap = icon.pixmap(Core::Constants::TARGET_ICON_SIZE); - painter.drawPixmap((Core::Constants::TARGET_ICON_SIZE - pixmap.width())/2, - (Core::Constants::TARGET_ICON_SIZE - pixmap.height())/2, pixmap); + QPainter painter(&targetPixmap); // painter in user space + + QPixmap pixmap = icon.pixmap(Core::Constants::TARGET_ICON_SIZE); // already takes app devicePixelRatio into account + qreal pixmapDevicePixelRatio = 1.0; +#if QT_VERSION >= 0x050100 + pixmapDevicePixelRatio = pixmap.devicePixelRatio(); +#endif + painter.drawPixmap((Core::Constants::TARGET_ICON_SIZE - pixmap.width() / pixmapDevicePixelRatio) / 2, + (Core::Constants::TARGET_ICON_SIZE - pixmap.height() / pixmapDevicePixelRatio) / 2, pixmap); if (!overlay.isNull()) { - pixmap = overlay.pixmap(Core::Constants::TARGET_ICON_SIZE); - painter.drawPixmap((Core::Constants::TARGET_ICON_SIZE - pixmap.width())/2, - (Core::Constants::TARGET_ICON_SIZE - pixmap.height())/2, pixmap); + pixmap = overlay.pixmap(Core::Constants::TARGET_ICON_SIZE); // already takes app devicePixelRatio into account + pixmapDevicePixelRatio = 1.0; +#if QT_VERSION >= 0x050100 + pixmapDevicePixelRatio = pixmap.devicePixelRatio(); +#endif + painter.drawPixmap((Core::Constants::TARGET_ICON_SIZE - pixmap.width() / pixmapDevicePixelRatio) / 2, + (Core::Constants::TARGET_ICON_SIZE - pixmap.height() / pixmapDevicePixelRatio) / 2, pixmap); } + return QIcon(targetPixmap); } diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc index 85ea369bbe..896b5dc4ab 100644 --- a/src/plugins/projectexplorer/projectexplorer.qrc +++ b/src/plugins/projectexplorer/projectexplorer.qrc @@ -23,6 +23,7 @@ <file>images/compile_error.png</file> <file>images/compile_warning.png</file> <file>images/BuildSettings.png</file> + <file>images/CodeStyleSettings.png</file> <file>images/RunSettings.png</file> <file>images/EditorSettings.png</file> <file>images/ProjectDependencies.png</file> diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp index 3211a8f35f..78c8fad0c2 100644 --- a/src/plugins/projectexplorer/target.cpp +++ b/src/plugins/projectexplorer/target.cpp @@ -551,15 +551,16 @@ void Target::updateDefaultDeployConfigurations() dcIds.append(dcFactory->availableCreationIds(this)); QList<DeployConfiguration *> dcList = deployConfigurations(); + QList<Core::Id> toCreate = dcIds; foreach (DeployConfiguration *dc, dcList) { if (dcIds.contains(dc->id())) - dcIds.removeOne(dc->id()); + toCreate.removeOne(dc->id()); else removeDeployConfiguration(dc); } - foreach (Core::Id id, dcIds) { + foreach (Core::Id id, toCreate) { foreach (DeployConfigurationFactory *dcFactory, dcFactories) { if (dcFactory->canCreate(this, id)) { DeployConfiguration *dc = dcFactory->create(this, id); diff --git a/src/plugins/projectexplorer/targetselector.h b/src/plugins/projectexplorer/targetselector.h index 7abe969682..f25f4f1de4 100644 --- a/src/plugins/projectexplorer/targetselector.h +++ b/src/plugins/projectexplorer/targetselector.h @@ -62,7 +62,10 @@ public: Target targetAt(int index) const; int targetCount() const { return m_targets.size(); } int currentIndex() const { return m_currentTargetIndex; } - int currentSubIndex() const { return m_targets.at(m_currentTargetIndex).currentSubIndex; } + int currentSubIndex() const { + return m_currentTargetIndex == -1 ? -1 + : m_targets.at(m_currentTargetIndex).currentSubIndex; + } void setTargetMenu(QMenu *menu); diff --git a/src/plugins/projectexplorer/task.cpp b/src/plugins/projectexplorer/task.cpp index 9f6796e1b8..a0a2079de3 100644 --- a/src/plugins/projectexplorer/task.cpp +++ b/src/plugins/projectexplorer/task.cpp @@ -32,6 +32,19 @@ namespace ProjectExplorer { +static QString taskTypeIcon(Task::TaskType t) +{ + switch (t) { + case Task::Warning: + return QLatin1String(":/projectexplorer/images/compile_warning.png"); + case Task::Error: + return QLatin1String(":/projectexplorer/images/compile_error.png"); + case Task::Unknown: + break; + } + return QString(); +} + unsigned int Task::s_nextId = 1; /*! @@ -44,9 +57,11 @@ Task::Task() : taskId(0), type(Unknown), line(-1) { } Task::Task(TaskType type_, const QString &description_, - const Utils::FileName &file_, int line_, Core::Id category_) : + const Utils::FileName &file_, int line_, Core::Id category_, + const Utils::FileName &iconFile) : taskId(s_nextId), type(type_), description(description_), - file(file_), line(line_), movedLine(line_), category(category_) + file(file_), line(line_), movedLine(line_), category(category_), + icon(iconFile.isEmpty() ? taskTypeIcon(type_) : iconFile.toString()) { ++s_nextId; } @@ -70,6 +85,7 @@ void Task::clear() movedLine = -1; category = Core::Id(); type = Task::Unknown; + icon = QIcon(); } // diff --git a/src/plugins/projectexplorer/task.h b/src/plugins/projectexplorer/task.h index 98782b201d..b387743027 100644 --- a/src/plugins/projectexplorer/task.h +++ b/src/plugins/projectexplorer/task.h @@ -54,7 +54,8 @@ public: Task(); Task(TaskType type, const QString &description, - const Utils::FileName &file, int line, Core::Id category); + const Utils::FileName &file, int line, Core::Id category, + const Utils::FileName &iconName = Utils::FileName()); bool isNull() const; void clear(); @@ -66,6 +67,7 @@ public: int line; int movedLine; // contains a line number if the line was moved in the editor Core::Id category; + QIcon icon; void addMark(TextEditor::BaseTextMark *mark); // Having a QList<QTextLayout::FormatRange> in Task isn't that great diff --git a/src/plugins/projectexplorer/taskhub.cpp b/src/plugins/projectexplorer/taskhub.cpp index 1cc702050b..0a45e0f090 100644 --- a/src/plugins/projectexplorer/taskhub.cpp +++ b/src/plugins/projectexplorer/taskhub.cpp @@ -117,7 +117,7 @@ void TaskHub::addTask(Task task) if (task.line != -1 && !task.file.isEmpty()) { bool visible = (task.type == Task::Warning || task.type == Task::Error); TaskMark *mark = new TaskMark(task.taskId, task.file.toString(), task.line, visible); - mark->setIcon(taskTypeIcon(task.type)); + mark->setIcon(task.icon); mark->setPriority(TextEditor::ITextMark::LowPriority); task.addMark(mark); emit m_instance->taskAdded(task); @@ -167,16 +167,3 @@ void TaskHub::requestPopup() emit m_instance->popupRequested(Core::IOutputPane::NoModeSwitch); } -QIcon TaskHub::taskTypeIcon(Task::TaskType t) -{ - switch (t) { - case Task::Warning: - return m_instance->m_warningIcon; - case Task::Error: - return m_instance->m_errorIcon; - case Task::Unknown: - break; - } - return QIcon(); -} - diff --git a/src/plugins/projectexplorer/taskhub.h b/src/plugins/projectexplorer/taskhub.h index 0c4f82e772..f47ea795e6 100644 --- a/src/plugins/projectexplorer/taskhub.h +++ b/src/plugins/projectexplorer/taskhub.h @@ -66,8 +66,6 @@ public: static void requestPopup(); - static QIcon taskTypeIcon(ProjectExplorer::Task::TaskType t); - signals: void categoryAdded(Core::Id categoryId, const QString &displayName, bool visible); void taskAdded(const ProjectExplorer::Task &task); diff --git a/src/plugins/projectexplorer/taskmodel.cpp b/src/plugins/projectexplorer/taskmodel.cpp index 85f38123f5..fd73b60118 100644 --- a/src/plugins/projectexplorer/taskmodel.cpp +++ b/src/plugins/projectexplorer/taskmodel.cpp @@ -30,6 +30,7 @@ #include "taskmodel.h" #include "task.h" +#include "taskhub.h" #include <utils/qtcassert.h> @@ -46,8 +47,6 @@ TaskModel::TaskModel(QObject *parent) : QAbstractItemModel(parent), m_maxSizeOfFileName(0), m_lastMaxSizeIndex(0), - m_errorIcon(QLatin1String(":/projectexplorer/images/compile_error.png")), - m_warningIcon(QLatin1String(":/projectexplorer/images/compile_warning.png")), m_sizeOfLineNumber(0) { m_categories.insert(Core::Id(), CategoryData()); @@ -83,19 +82,6 @@ bool TaskModel::hasFile(const QModelIndex &index) const return !m_tasks.at(row).file.isEmpty(); } -QIcon TaskModel::taskTypeIcon(Task::TaskType t) const -{ - switch (t) { - case Task::Warning: - return m_warningIcon; - case Task::Error: - return m_errorIcon; - case Task::Unknown: - break; - } - return QIcon(); -} - void TaskModel::addCategory(const Core::Id &categoryId, const QString &categoryName) { QTC_ASSERT(categoryId.uniqueIdentifier(), return); @@ -269,7 +255,7 @@ QVariant TaskModel::data(const QModelIndex &index, int role) const else if (role == TaskModel::Category) return m_tasks.at(index.row()).category.uniqueIdentifier(); else if (role == TaskModel::Icon) - return taskTypeIcon(m_tasks.at(index.row()).type); + return m_tasks.at(index.row()).icon; else if (role == TaskModel::Task_t) return QVariant::fromValue(task(index)); return QVariant(); diff --git a/src/plugins/projectexplorer/taskmodel.h b/src/plugins/projectexplorer/taskmodel.h index 5d98a6436b..852c11ca45 100644 --- a/src/plugins/projectexplorer/taskmodel.h +++ b/src/plugins/projectexplorer/taskmodel.h @@ -71,8 +71,6 @@ public: enum Roles { File = Qt::UserRole, Line, MovedLine, Description, FileNotFound, Type, Category, Icon, Task_t }; - QIcon taskTypeIcon(Task::TaskType t) const; - int taskCount(const Core::Id &categoryId); int errorTaskCount(const Core::Id &categoryId); int warningTaskCount(const Core::Id &categoryId); @@ -125,8 +123,6 @@ private: int m_maxSizeOfFileName; int m_lastMaxSizeIndex; QFont m_fileMeasurementFont; - const QIcon m_errorIcon; - const QIcon m_warningIcon; int m_sizeOfLineNumber; QFont m_lineMeasurementFont; }; diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index a056d96ec7..08206252d2 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -261,9 +261,9 @@ TaskWindow::TaskWindow() : d(new TaskWindowPrivate) d->m_listview->setContextMenuPolicy(Qt::ActionsContextMenu); - d->m_filterWarningsButton = createFilterButton(d->m_model->taskTypeIcon(Task::Warning), - tr("Show Warnings"), - this, SLOT(setShowWarnings(bool))); + d->m_filterWarningsButton = createFilterButton( + QIcon(QLatin1String(":/projectexplorer/images/compile_warning.png")), + tr("Show Warnings"), this, SLOT(setShowWarnings(bool))); d->m_categoriesButton = new QToolButton; d->m_categoriesButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_FILTER))); diff --git a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp index 853227da67..ca3ccfa16d 100644 --- a/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp +++ b/src/plugins/qbsprojectmanager/defaultpropertyprovider.cpp @@ -95,9 +95,19 @@ QVariantMap DefaultPropertyProvider::properties(const ProjectExplorer::Kit *k, c ? QStringList() << QLatin1String("mingw") << QLatin1String("gcc") : QStringList() << QLatin1String("msvc")); } else if (targetAbi.os() == ProjectExplorer::Abi::MacOS) { - data.insert(QLatin1String(QBS_TARGETOS), QStringList() << QLatin1String("osx") - << QLatin1String("darwin") << QLatin1String("bsd4") - << QLatin1String("bsd") << QLatin1String("unix")); + const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios"; // from Ios::Constants (include header?) + if (qt && qt->type() == QLatin1String(IOSQT)) { + QStringList targetOS; + if (targetAbi.architecture() == ProjectExplorer::Abi::X86Architecture) + targetOS << QLatin1String("ios-simulator"); + targetOS << QLatin1String("ios") << QLatin1String("darwin") + << QLatin1String("bsd4") << QLatin1String("bsd") << QLatin1String("unix"); + data.insert(QLatin1String(QBS_TARGETOS), targetOS); + } else { + data.insert(QLatin1String(QBS_TARGETOS), QStringList() << QLatin1String("osx") + << QLatin1String("darwin") << QLatin1String("bsd4") + << QLatin1String("bsd") << QLatin1String("unix")); + } if (tc->type() != QLatin1String("clang")) { data.insert(QLatin1String(QBS_TOOLCHAIN), QLatin1String("gcc")); } else { @@ -117,6 +127,17 @@ QVariantMap DefaultPropertyProvider::properties(const ProjectExplorer::Kit *k, c << QLatin1String("llvm") << QLatin1String("gcc")); } + } else { + // TODO: Factor out toolchain type setting. + data.insert(QLatin1String(QBS_TARGETOS), QStringList() << QLatin1String("unix")); + if (tc->type() != QLatin1String("clang")) { + data.insert(QLatin1String(QBS_TOOLCHAIN), QLatin1String("gcc")); + } else { + data.insert(QLatin1String(QBS_TOOLCHAIN), + QStringList() << QLatin1String("clang") + << QLatin1String("llvm") + << QLatin1String("gcc")); + } } Utils::FileName cxx = tc->compilerCommand(); data.insert(QLatin1String(CPP_TOOLCHAINPATH), cxx.toFileInfo().absolutePath()); diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index 66e7802111..c087d334a6 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -50,6 +50,7 @@ static const char QBS_CONFIG[] = "Qbs.Configuration"; static const char QBS_DRY_RUN[] = "Qbs.DryRun"; static const char QBS_KEEP_GOING[] = "Qbs.DryKeepGoing"; +static const char QBS_CHECK_TIMESTAMPS[] = "Qbs.CheckTimestamps"; static const char QBS_MAXJOBCOUNT[] = "Qbs.MaxJobs"; // -------------------------------------------------------------------- @@ -69,6 +70,7 @@ QbsBuildStep::QbsBuildStep(ProjectExplorer::BuildStepList *bsl) : { setDisplayName(tr("Qbs Build")); setQbsConfiguration(QVariantMap()); + m_qbsBuildOptions.setForceTimestampCheck(true); } QbsBuildStep::QbsBuildStep(ProjectExplorer::BuildStepList *bsl, const QbsBuildStep *other) : @@ -194,6 +196,11 @@ bool QbsBuildStep::keepGoing() const return m_qbsBuildOptions.keepGoing(); } +bool QbsBuildStep::checkTimestamps() const +{ + return m_qbsBuildOptions.forceTimestampCheck(); +} + int QbsBuildStep::maxJobs() const { if (m_qbsBuildOptions.maxJobCount() > 0) @@ -209,6 +216,7 @@ bool QbsBuildStep::fromMap(const QVariantMap &map) setQbsConfiguration(map.value(QLatin1String(QBS_CONFIG)).toMap()); m_qbsBuildOptions.setDryRun(map.value(QLatin1String(QBS_DRY_RUN)).toBool()); m_qbsBuildOptions.setKeepGoing(map.value(QLatin1String(QBS_KEEP_GOING)).toBool()); + m_qbsBuildOptions.setForceTimestampCheck(map.value(QLatin1String(QBS_CHECK_TIMESTAMPS), true).toBool()); m_qbsBuildOptions.setMaxJobCount(map.value(QLatin1String(QBS_MAXJOBCOUNT)).toInt()); return true; } @@ -219,6 +227,7 @@ QVariantMap QbsBuildStep::toMap() const map.insert(QLatin1String(QBS_CONFIG), m_qbsConfiguration); map.insert(QLatin1String(QBS_DRY_RUN), m_qbsBuildOptions.dryRun()); map.insert(QLatin1String(QBS_KEEP_GOING), m_qbsBuildOptions.keepGoing()); + map.insert(QLatin1String(QBS_CHECK_TIMESTAMPS), m_qbsBuildOptions.forceTimestampCheck()); map.insert(QLatin1String(QBS_MAXJOBCOUNT), m_qbsBuildOptions.maxJobCount()); return map; } @@ -333,6 +342,14 @@ void QbsBuildStep::setKeepGoing(bool kg) emit qbsBuildOptionsChanged(); } +void QbsBuildStep::setCheckTimestamps(bool ts) +{ + if (m_qbsBuildOptions.forceTimestampCheck() == ts) + return; + m_qbsBuildOptions.setForceTimestampCheck(ts); + emit qbsBuildOptionsChanged(); +} + void QbsBuildStep::setMaxJobs(int jobcount) { if (m_qbsBuildOptions.maxJobCount() == jobcount) @@ -362,6 +379,8 @@ QbsBuildStepConfigWidget::QbsBuildStepConfigWidget(QbsBuildStep *step) : this, SLOT(changeBuildVariant(int))); connect(m_ui->dryRunCheckBox, SIGNAL(toggled(bool)), this, SLOT(changeDryRun(bool))); connect(m_ui->keepGoingCheckBox, SIGNAL(toggled(bool)), this, SLOT(changeKeepGoing(bool))); + connect(m_ui->checkTimestampCheckBox, SIGNAL(toggled(bool)), + this, SLOT(changeCheckTimestamps(bool))); connect(m_ui->jobSpinBox, SIGNAL(valueChanged(int)), this, SLOT(changeJobCount(int))); connect(m_ui->propertyEdit, SIGNAL(propertiesChanged()), this, SLOT(changeProperties())); connect(m_ui->qmlDebuggingLibraryCheckBox, SIGNAL(toggled(bool)), @@ -386,6 +405,7 @@ void QbsBuildStepConfigWidget::updateState() if (!m_ignoreChange) { m_ui->dryRunCheckBox->setChecked(m_step->dryRun()); m_ui->keepGoingCheckBox->setChecked(m_step->keepGoing()); + m_ui->checkTimestampCheckBox->setChecked(m_step->checkTimestamps()); m_ui->jobSpinBox->setValue(m_step->maxJobs()); updatePropertyEdit(m_step->qbsConfiguration()); m_ui->qmlDebuggingLibraryCheckBox->setChecked(m_step->isQmlDebuggingEnabled()); @@ -402,6 +422,8 @@ void QbsBuildStepConfigWidget::updateState() command += QLatin1String("--dry-run "); if (m_step->keepGoing()) command += QLatin1String("--keep-going "); + if (m_step->checkTimestamps()) + command += QLatin1String("--check-timestamps "); command += QString::fromLatin1("--jobs %1 ").arg(m_step->maxJobs()); command += QString::fromLatin1("%1 profile:%2").arg(buildVariant, m_step->profile()); @@ -480,6 +502,13 @@ void QbsBuildStepConfigWidget::changeKeepGoing(bool kg) m_ignoreChange = false; } +void QbsBuildStepConfigWidget::changeCheckTimestamps(bool ts) +{ + m_ignoreChange = true; + m_step->setCheckTimestamps(ts); + m_ignoreChange = false; +} + void QbsBuildStepConfigWidget::changeJobCount(int count) { m_ignoreChange = true; diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.h b/src/plugins/qbsprojectmanager/qbsbuildstep.h index f1ec50f67b..ba123fb5e8 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.h +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.h @@ -65,6 +65,7 @@ public: bool dryRun() const; bool keepGoing() const; + bool checkTimestamps() const; int maxJobs() const; QString buildVariant() const; @@ -93,6 +94,7 @@ private: void setDryRun(bool dr); void setKeepGoing(bool kg); + void setCheckTimestamps(bool ts); void setMaxJobs(int jobcount); QVariantMap m_qbsConfiguration; @@ -129,6 +131,7 @@ private slots: void changeBuildVariant(int); void changeDryRun(bool dr); void changeKeepGoing(bool kg); + void changeCheckTimestamps(bool ts); void changeJobCount(int count); void changeProperties(); diff --git a/src/plugins/qbsprojectmanager/qbsbuildstepconfigwidget.ui b/src/plugins/qbsprojectmanager/qbsbuildstepconfigwidget.ui index d527af4f96..52767a8103 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstepconfigwidget.ui +++ b/src/plugins/qbsprojectmanager/qbsbuildstepconfigwidget.ui @@ -168,6 +168,13 @@ </widget> </item> <item> + <widget class="QCheckBox" name="checkTimestampCheckBox"> + <property name="text"> + <string>Check timestamps</string> + </property> + </widget> + </item> + <item> <spacer name="checkBoxSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 9c4184c539..29340aae58 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -112,7 +112,7 @@ QbsProject::QbsProject(QbsManager *manager, const QString &fileName) : this, SLOT(targetWasAdded(ProjectExplorer::Target*))); connect(this, SIGNAL(environmentChanged()), this, SLOT(delayParsing())); - connect(&m_parsingDelay, SIGNAL(timeout()), this, SLOT(parseCurrentBuildConfiguration())); + connect(&m_parsingDelay, SIGNAL(timeout()), this, SLOT(startParsing())); updateDocuments(QSet<QString>() << fileName); @@ -357,6 +357,11 @@ void QbsProject::buildConfigurationChanged(BuildConfiguration *bc) } } +void QbsProject::startParsing() +{ + parseCurrentBuildConfiguration(false); +} + void QbsProject::delayParsing() { m_parsingDelay.start(); @@ -368,10 +373,13 @@ void QbsProject::delayForcedParsing() delayParsing(); } -void QbsProject::parseCurrentBuildConfiguration() +void QbsProject::parseCurrentBuildConfiguration(bool force) { m_parsingDelay.stop(); + if (!m_forceParsing) + m_forceParsing = force; + if (!activeTarget()) return; QbsBuildConfiguration *bc = qobject_cast<QbsBuildConfiguration *>(activeTarget()->activeBuildConfiguration()); @@ -635,7 +643,7 @@ void QbsProject::updateCppCodeModel(const qbs::ProjectData &prj) part->includePaths += grpIncludePaths; part->frameworkPaths += grpFrameworkPaths; part->precompiledHeaders = QStringList(pch); - part->defines += grpDefines; + part->projectDefines += grpDefines; pinfo.appendProjectPart(part); } } diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h index d43ead569c..d113684a93 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.h +++ b/src/plugins/qbsprojectmanager/qbsproject.h @@ -90,6 +90,7 @@ public: QString profileForTarget(const ProjectExplorer::Target *t) const; bool isParsing() const; bool hasParseResult() const; + void parseCurrentBuildConfiguration(bool force); Utils::FileName defaultBuildDirectory() const; static Utils::FileName defaultBuildDirectory(const QString &path); @@ -101,7 +102,6 @@ public: public slots: void invalidate(); - void parseCurrentBuildConfiguration(); void delayParsing(); void delayForcedParsing(); @@ -117,6 +117,7 @@ private slots: void targetWasAdded(ProjectExplorer::Target *t); void changeActiveTarget(ProjectExplorer::Target *t); void buildConfigurationChanged(ProjectExplorer::BuildConfiguration *bc); + void startParsing(); private: bool fromMap(const QVariantMap &map); diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanager.pro b/src/plugins/qbsprojectmanager/qbsprojectmanager.pro index 47e40a1f22..3b8da1c508 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanager.pro +++ b/src/plugins/qbsprojectmanager/qbsprojectmanager.pro @@ -36,7 +36,6 @@ HEADERS = \ qbsprojectmanagerplugin.h \ qbspropertylineedit.h \ qbsrunconfiguration.h \ - qbsstep.h \ qbsconstants.h SOURCES = \ @@ -55,8 +54,7 @@ SOURCES = \ qbsprojectmanager.cpp \ qbsprojectmanagerplugin.cpp \ qbspropertylineedit.cpp \ - qbsrunconfiguration.cpp \ - qbsstep.cpp + qbsrunconfiguration.cpp FORMS = \ qbsbuildstepconfigwidget.ui \ diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs b/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs index af2759e317..b4e8ab2420 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs +++ b/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs @@ -96,9 +96,7 @@ QtcPlugin { "qbspropertylineedit.cpp", "qbspropertylineedit.h", "qbsrunconfiguration.cpp", - "qbsrunconfiguration.h", - "qbsstep.cpp", - "qbsstep.h" + "qbsrunconfiguration.h" ] } diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp index f02597b715..070d424886 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp @@ -405,7 +405,7 @@ void QbsProjectManagerPlugin::buildProducts(QbsProject *project, const QStringLi void QbsProjectManagerPlugin::reparseCurrentProject() { if (m_currentProject) - m_currentProject->parseCurrentBuildConfiguration(); + m_currentProject->parseCurrentBuildConfiguration(true); } } // namespace Internal diff --git a/src/plugins/qbsprojectmanager/qbsstep.cpp b/src/plugins/qbsprojectmanager/qbsstep.cpp deleted file mode 100644 index b4aee3534e..0000000000 --- a/src/plugins/qbsprojectmanager/qbsstep.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "qbsstep.h" - -#include "qbsbuildconfiguration.h" -#include "qbsparser.h" -#include "qbsproject.h" -#include "qbsprojectmanagerconstants.h" - -#include <projectexplorer/buildsteplist.h> -#include <projectexplorer/kit.h> -#include <projectexplorer/projectexplorerconstants.h> -#include <projectexplorer/target.h> -#include <utils/qtcassert.h> - -#include <qbs.h> - -#include <QTimer> - -// -------------------------------------------------------------------- -// Constants: -// -------------------------------------------------------------------- - -static const char QBS_DRY_RUN[] = "Qbs.DryRun"; -static const char QBS_KEEP_GOING[] = "Qbs.DryKeepGoing"; -static const char QBS_MAXJOBCOUNT[] = "Qbs.MaxJobs"; - -namespace QbsProjectManager { -namespace Internal { - -// -------------------------------------------------------------------- -// QbsStep: -// -------------------------------------------------------------------- - -QbsStep::QbsStep(ProjectExplorer::BuildStepList *bsl, Core::Id id) : - ProjectExplorer::BuildStep(bsl, id), - m_job(0) -{ - m_qbsBuildOptions.setMaxJobCount(QbsManager::preferences()->jobs()); -} - -QbsStep::QbsStep(ProjectExplorer::BuildStepList *bsl, const QbsStep *other) : - ProjectExplorer::BuildStep(bsl, Core::Id(Constants::QBS_BUILDSTEP_ID)), - m_qbsBuildOptions(other->m_qbsBuildOptions), m_job(0) -{ } - -QbsBuildConfiguration *QbsStep::currentBuildConfiguration() const -{ - QbsBuildConfiguration *bc = static_cast<QbsBuildConfiguration *>(buildConfiguration()); - if (!bc) - bc = static_cast<QbsBuildConfiguration *>(target()->activeBuildConfiguration()); - return bc; -} - -QbsStep::~QbsStep() -{ - cancel(); - m_job->deleteLater(); - m_job = 0; -} - -bool QbsStep::init() -{ - if (static_cast<QbsProject *>(project())->isParsing() || m_job) - return false; - - if (!currentBuildConfiguration()) - return false; - - return true; -} - -void QbsStep::run(QFutureInterface<bool> &fi) -{ - m_fi = &fi; - - m_job = createJob(); - - if (!m_job) { - jobDone(false); - return; - } - - m_progressBase = 0; - - connect(m_job, SIGNAL(finished(bool,qbs::AbstractJob*)), this, SLOT(jobDone(bool))); - connect(m_job, SIGNAL(taskStarted(QString,int,qbs::AbstractJob*)), - this, SLOT(handleTaskStarted(QString,int))); - connect(m_job, SIGNAL(taskProgress(int,qbs::AbstractJob*)), - this, SLOT(handleProgress(int))); -} - -QFutureInterface<bool> *QbsStep::future() const -{ - return m_fi; -} - -bool QbsStep::runInGuiThread() const -{ - return true; -} - -void QbsStep::cancel() -{ - if (m_job) - m_job->cancel(); -} - -bool QbsStep::dryRun() const -{ - return m_qbsBuildOptions.dryRun(); -} - -bool QbsStep::keepGoing() const -{ - return m_qbsBuildOptions.keepGoing(); -} - -int QbsStep::maxJobs() const -{ - return m_qbsBuildOptions.maxJobCount(); -} - -bool QbsStep::fromMap(const QVariantMap &map) -{ - if (!ProjectExplorer::BuildStep::fromMap(map)) - return false; - - m_qbsBuildOptions.setDryRun(map.value(QLatin1String(QBS_DRY_RUN)).toBool()); - m_qbsBuildOptions.setKeepGoing(map.value(QLatin1String(QBS_KEEP_GOING)).toBool()); - m_qbsBuildOptions.setMaxJobCount(map.value(QLatin1String(QBS_MAXJOBCOUNT)).toInt()); - - if (m_qbsBuildOptions.maxJobCount() <= 0) - m_qbsBuildOptions.setMaxJobCount(QbsManager::preferences()->jobs()); - - return true; -} - -QVariantMap QbsStep::toMap() const -{ - QVariantMap map = ProjectExplorer::BuildStep::toMap(); - map.insert(QLatin1String(QBS_DRY_RUN), m_qbsBuildOptions.dryRun()); - map.insert(QLatin1String(QBS_KEEP_GOING), m_qbsBuildOptions.keepGoing()); - map.insert(QLatin1String(QBS_MAXJOBCOUNT), m_qbsBuildOptions.maxJobCount()); - return map; -} - -void QbsStep::jobDone(bool success) -{ - // Report errors: - if (m_job) { - foreach (const qbs::ErrorItem &item, m_job->error().items()) - createTaskAndOutput(ProjectExplorer::Task::Error, item.description(), - item.codeLocation().fileName(), item.codeLocation().line()); - m_job->deleteLater(); - m_job = 0; - } - - QTC_ASSERT(m_fi, return); - m_fi->reportResult(success); - m_fi = 0; // do not delete, it is not ours - - emit finished(); -} - -void QbsStep::handleTaskStarted(const QString &desciption, int max) -{ - Q_UNUSED(desciption); - QTC_ASSERT(m_fi, return); - - m_progressBase = m_fi->progressValue(); - m_fi->setProgressRange(0, m_progressBase + max); -} - -void QbsStep::handleProgress(int value) -{ - QTC_ASSERT(m_fi, return); - m_fi->setProgressValue(m_progressBase + value); -} - -void QbsStep::createTaskAndOutput(ProjectExplorer::Task::TaskType type, const QString &message, - const QString &file, int line) -{ - emit addTask(ProjectExplorer::Task(type, message, - Utils::FileName::fromString(file), line, - ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)); - emit addOutput(message, NormalOutput); -} - -void QbsStep::setDryRun(bool dr) -{ - if (m_qbsBuildOptions.dryRun() == dr) - return; - m_qbsBuildOptions.setDryRun(dr); - emit qbsBuildOptionsChanged(); -} - -void QbsStep::setKeepGoing(bool kg) -{ - if (m_qbsBuildOptions.keepGoing() == kg) - return; - m_qbsBuildOptions.setKeepGoing(kg); - emit qbsBuildOptionsChanged(); -} - -void QbsStep::setMaxJobs(int jobcount) -{ - if (m_qbsBuildOptions.maxJobCount() == jobcount) - return; - m_qbsBuildOptions.setMaxJobCount(jobcount); - emit qbsBuildOptionsChanged(); -} - -} // namespace Internal -} // namespace QbsProjectManager diff --git a/src/plugins/qbsprojectmanager/qbsstep.h b/src/plugins/qbsprojectmanager/qbsstep.h deleted file mode 100644 index 3728f237b1..0000000000 --- a/src/plugins/qbsprojectmanager/qbsstep.h +++ /dev/null @@ -1,108 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#ifndef QBSSTEP_H -#define QBSSTEP_H - -#include "qbsbuildconfiguration.h" - -#include <projectexplorer/buildstep.h> -#include <projectexplorer/task.h> - -#include <qbs.h> - -namespace QbsProjectManager { -namespace Internal { - -class QbsStepConfigWidget; - -class QbsStep : public ProjectExplorer::BuildStep -{ - Q_OBJECT - -public: - ~QbsStep(); - - bool init(); - - void run(QFutureInterface<bool> &fi); - - QFutureInterface<bool> *future() const; - - bool runInGuiThread() const; - void cancel(); - - bool dryRun() const; - bool keepGoing() const; - int maxJobs() const; - QString buildVariant() const; - - bool fromMap(const QVariantMap &map); - QVariantMap toMap() const; - -signals: - void qbsBuildOptionsChanged(); - -private slots: - virtual void jobDone(bool success); - void handleTaskStarted(const QString &desciption, int max); - void handleProgress(int value); - -protected: - QbsStep(ProjectExplorer::BuildStepList *bsl, Core::Id id); - QbsStep(ProjectExplorer::BuildStepList *bsl, const QbsStep *other); - - QbsBuildConfiguration *currentBuildConfiguration() const; - - virtual qbs::AbstractJob *createJob() = 0; - - void createTaskAndOutput(ProjectExplorer::Task::TaskType type, - const QString &message, const QString &file, int line); - - qbs::AbstractJob *job() const { return m_job; } - qbs::BuildOptions buildOptions() const { return m_qbsBuildOptions; } - -private: - void setDryRun(bool dr); - void setKeepGoing(bool kg); - void setMaxJobs(int jobcount); - - qbs::BuildOptions m_qbsBuildOptions; - - QFutureInterface<bool> *m_fi; - qbs::AbstractJob *m_job; - int m_progressBase; - - friend class QbsStepConfigWidget; -}; - -} // namespace Internal -} // namespace QbsProjectManager - -#endif // QBSSTEP_H diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index b4ed6335e0..7da38ea3f9 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -89,8 +89,8 @@ QmakeBuildConfiguration *enableActiveQmakeBuildConfiguration(ProjectExplorer::Ta void updateBoilerPlateCodeFiles(const AbstractMobileApp *app, const QString &proFile) { - const QList<AbstractGeneratedFileInfo> updates = - app->fileUpdates(proFile); + const QList<AbstractGeneratedFileInfo> updates = app->fileUpdates(proFile); + const QString nativeProFile = QDir::toNativeSeparators(proFile); if (!updates.empty()) { const QString title = QmakeManager::tr("Update of Generated Files"); QStringList fileNames; @@ -100,7 +100,7 @@ void updateBoilerPlateCodeFiles(const AbstractMobileApp *app, const QString &pro QmakeManager::tr("In project<br><br>%1<br><br>The following files are either " "outdated or have been modified:<br><br>%2<br><br>Do you want " "Qt Creator to update the files? Any changes will be lost.") - .arg(proFile, fileNames.join(QLatin1String(", "))); + .arg(nativeProFile, fileNames.join(QLatin1String(", "))); if (QMessageBox::question(0, title, message, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { QString error; if (!app->updateFiles(updates, error)) @@ -528,7 +528,7 @@ void QmakeProject::updateCppCodeModel() SysRootKitInformation::sysRoot(k)); // part->defines - part->defines += pro->cxxDefines(); + part->projectDefines += pro->cxxDefines(); // part->includePaths, part->frameworkPaths part->includePaths.append(pro->variableValue(IncludePathVar)); diff --git a/src/plugins/qmakeprojectmanager/wizards/abstractmobileapp.h b/src/plugins/qmakeprojectmanager/wizards/abstractmobileapp.h index 50326eb78a..fba657b0c1 100644 --- a/src/plugins/qmakeprojectmanager/wizards/abstractmobileapp.h +++ b/src/plugins/qmakeprojectmanager/wizards/abstractmobileapp.h @@ -121,6 +121,7 @@ public: static const QString DeploymentPriFileName; protected: AbstractMobileApp(); + virtual QByteArray generateProFile(QString *errorMessage) const; static QString templatesRoot(); static void insertParameter(QString &line, const QString ¶meter); @@ -146,7 +147,6 @@ protected: private: QByteArray generateDesktopFile(QString *errorMessage, int fileType) const; QByteArray generateMainCpp(QString *errorMessage) const; - QByteArray generateProFile(QString *errorMessage) const; virtual QByteArray generateFileExtended(int fileType, bool *versionAndCheckSum, QString *comment, QString *errorMessage) const = 0; diff --git a/src/plugins/qmakeprojectmanager/wizards/qtquickapp.cpp b/src/plugins/qmakeprojectmanager/wizards/qtquickapp.cpp index 169afe0cac..b5833254dd 100644 --- a/src/plugins/qmakeprojectmanager/wizards/qtquickapp.cpp +++ b/src/plugins/qmakeprojectmanager/wizards/qtquickapp.cpp @@ -44,6 +44,11 @@ namespace QmakeProjectManager { namespace Internal { +static QString qtQuickApplicationViewerDirectory() +{ + return Core::ICore::resourcePath() + QLatin1String("/templates/shared/qtquickapplicationviewer/"); +} + static QString templateRootDirectory() { return Core::ICore::resourcePath() + QLatin1String("/templates/qtquick/"); @@ -208,11 +213,11 @@ QString QtQuickApp::pathExtended(int fileType) const case MainQmlDeployed: return qmlSubDir + mainQmlFile; case MainQmlOrigin: return qmlOriginDir + mainQmlFile; case AppViewerPri: return pathBase + appViewerTargetSubDir + fileName(AppViewerPri); - case AppViewerPriOrigin: return originsRoot() + appViewerOriginSubDir() + fileName(AppViewerPri); + case AppViewerPriOrigin: return qtQuickApplicationViewerDirectory() + appViewerOriginSubDir() + fileName(AppViewerPri); case AppViewerCpp: return pathBase + appViewerTargetSubDir + fileName(AppViewerCpp); - case AppViewerCppOrigin: return originsRoot() + appViewerOriginSubDir() + fileName(AppViewerCpp); + case AppViewerCppOrigin: return qtQuickApplicationViewerDirectory() + appViewerOriginSubDir() + fileName(AppViewerCpp); case AppViewerH: return pathBase + appViewerTargetSubDir + fileName(AppViewerH); - case AppViewerHOrigin: return originsRoot() + appViewerOriginSubDir() + fileName(AppViewerH); + case AppViewerHOrigin: return qtQuickApplicationViewerDirectory() + appViewerOriginSubDir() + fileName(AppViewerH); case QmlDirProFileRelative: return QString(qmlSubDir).remove(qmlSubDir.length() - 1, 1); default: qFatal("QtQuickApp::pathExtended() needs more work"); } @@ -294,6 +299,13 @@ QString QtQuickApp::appViewerOriginSubDir() const return appViewerBaseName() + QLatin1Char('/'); } +QByteArray QtQuickApp::generateProFile(QString *errorMessage) const +{ + QByteArray proFileContent = AbstractMobileApp::generateProFile(errorMessage); + proFileContent.replace("../../shared/qtquickapplicationviewer/", ""); + return proFileContent; +} + QByteArray QtQuickApp::generateFileExtended(int fileType, bool *versionAndCheckSum, QString *comment, QString *errorMessage) const { diff --git a/src/plugins/qmakeprojectmanager/wizards/qtquickapp.h b/src/plugins/qmakeprojectmanager/wizards/qtquickapp.h index e421a42dcb..b7381ed465 100644 --- a/src/plugins/qmakeprojectmanager/wizards/qtquickapp.h +++ b/src/plugins/qmakeprojectmanager/wizards/qtquickapp.h @@ -95,7 +95,9 @@ public: static const int StubVersion; protected: - virtual QString appViewerBaseName() const; + virtual QByteArray generateProFile(QString *errorMessage) const; + + QString appViewerBaseName() const; QString fileName(ExtendedFileType type) const; QString appViewerOriginSubDir() const; diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp index 677d79d20f..1881169afe 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp @@ -204,10 +204,7 @@ void StatesEditorView::addState() try { if ((rootStateGroup().allStates().count() < 1) && //QtQuick import might be missing - (!model()->hasImport(Import::createLibraryImport("QtQuick", "1.0"), true) - && !model()->hasImport(Import::createLibraryImport("QtQuick", "1.1"), true) - && !model()->hasImport(Import::createLibraryImport("QtQuick", "2.0"), true) - && !model()->hasImport(Import::createLibraryImport("QtQuick", "2.1"), true))) + (!model()->hasImport(Import::createLibraryImport("QtQuick", "1.0"), true, true))) model()->changeImports(QList<Import>() << Import::createLibraryImport("QtQuick", "1.0"), QList<Import>()); ModelNode newState = rootStateGroup().addState(newStateName); setCurrentState(newState); diff --git a/src/plugins/qmldesigner/components/stateseditor/stateslist.qml b/src/plugins/qmldesigner/components/stateseditor/stateslist.qml index b13bc6fdb9..901486f1e4 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateslist.qml +++ b/src/plugins/qmldesigner/components/stateseditor/stateslist.qml @@ -161,8 +161,8 @@ Rectangle { width:100 height:100 - anchors.left: parent.left - anchors.leftMargin: (parent.width - width - container.baseStateOffset)/2 + anchors.horizontalCenter: parent.horizontalCenter + anchors.horizontalCenterOffset: -container.baseStateOffset / 2 anchors.bottom: parent.bottom anchors.bottomMargin: 9 Image { diff --git a/src/plugins/qmldesigner/settingspage.ui b/src/plugins/qmldesigner/settingspage.ui index c8f5452e66..528f621d13 100644 --- a/src/plugins/qmldesigner/settingspage.ui +++ b/src/plugins/qmldesigner/settingspage.ui @@ -24,9 +24,6 @@ <layout class="QFormLayout" name="formLayout_4"> <item row="0" column="1"> <widget class="QCheckBox" name="designerShowDebuggerCheckBox"> - <property name="toolTip"> - <string>Warn about QML features which are not properly supported by the Qt Quick Designer</string> - </property> <property name="text"> <string>Show the debugging view</string> </property> @@ -34,9 +31,6 @@ </item> <item row="1" column="1"> <widget class="QCheckBox" name="designerEnableDebuggerCheckBox"> - <property name="toolTip"> - <string>Also warn in the code editor about QML features which are not properly supported by the Qt Quick Designer</string> - </property> <property name="text"> <string>Enable the debugging view</string> </property> @@ -64,7 +58,7 @@ <item row="0" column="1"> <widget class="QCheckBox" name="designerWarningsCheckBox"> <property name="toolTip"> - <string>Warn about QML features which are not properly supported by the Qt Quick Designer</string> + <string>Warns about QML features which are not properly supported by the Qt Quick Designer</string> </property> <property name="text"> <string>Warn about unsupported features in the Qt Quick Designer</string> @@ -74,7 +68,7 @@ <item row="1" column="1"> <widget class="QCheckBox" name="designerWarningsInEditorCheckBox"> <property name="toolTip"> - <string>Also warn in the code editor about QML features which are not properly supported by the Qt Quick Designer</string> + <string>Also warns in the code editor about QML features which are not properly supported by the Qt Quick Designer</string> </property> <property name="text"> <string>Warn about unsupported features of Qt Quick Designer in the code editor</string> diff --git a/src/plugins/qmljseditor/qmljscompletionassist.cpp b/src/plugins/qmljseditor/qmljscompletionassist.cpp index 65a80f6d29..16661622d3 100644 --- a/src/plugins/qmljseditor/qmljscompletionassist.cpp +++ b/src/plugins/qmljseditor/qmljscompletionassist.cpp @@ -985,13 +985,16 @@ const SemanticInfo &QmlJSCompletionAssistInterface::semanticInfo() const namespace { -struct QmlJSLessThan +class QmlJSLessThan { +public: + QmlJSLessThan(const QString &searchString) : m_searchString(searchString) + { } bool operator() (const BasicProposalItem *a, const BasicProposalItem *b) { if (a->order() != b->order()) return a->order() > b->order(); - else if (a->text().isEmpty()) + else if (a->text().isEmpty() && ! b->text().isEmpty()) return true; else if (b->text().isEmpty()) return false; @@ -1001,8 +1004,14 @@ struct QmlJSLessThan return false; else if (a->text().at(0).isLower() && b->text().at(0).isUpper()) return true; + int m1 = PersistentTrie::matchStrength(m_searchString, a->text()); + int m2 = PersistentTrie::matchStrength(m_searchString, b->text()); + if (m1 != m2) + return m1 > m2; return a->text() < b->text(); } +private: + QString m_searchString; }; } // Anonymous @@ -1023,9 +1032,9 @@ void QmlJSAssistProposalModel::filter(const QString &prefix) m_currentItems = newCurrentItems; } -void QmlJSAssistProposalModel::sort(const QString &) +void QmlJSAssistProposalModel::sort(const QString &prefix) { - qSort(currentItems().first, currentItems().second, QmlJSLessThan()); + qSort(currentItems().first, currentItems().second, QmlJSLessThan(prefix)); } bool QmlJSAssistProposalModel::keepPerfectMatch(TextEditor::AssistReason reason) const diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index 61470f40c2..36324371c4 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -232,6 +232,7 @@ QStringList QmlJSTools::qmlAndJsGlobPatterns() ModelManager::ModelManager(QObject *parent): ModelManagerInterface(parent), + m_shouldScanImports(false), m_pluginDumper(new PluginDumper(this)) { m_synchronizer.setCancelOnWait(true); @@ -328,7 +329,7 @@ ModelManagerInterface::WorkingCopy ModelManager::workingCopy() const if (TextEditor::BaseTextDocument *textDocument = qobject_cast<TextEditor::BaseTextDocument *>(document)) { // TODO the language should be a property on the document, not the editor if (documentModel->editorsForDocument(document).first()->context().contains(ProjectExplorer::Constants::LANG_QMLJS)) - workingCopy.insert(key, textDocument->contents(), textDocument->document()->revision()); + workingCopy.insert(key, textDocument->plainText(), textDocument->document()->revision()); } } @@ -380,6 +381,20 @@ QFuture<void> ModelManager::refreshSourceFiles(const QStringList &sourceFiles, if (sourceFiles.count() > 1) ProgressManager::addTask(result, tr("Indexing"), Constants::TASK_INDEX); + if (sourceFiles.count() > 1 && !m_shouldScanImports) { + bool scan = false; + { + QMutexLocker l(&m_mutex); + if (!m_shouldScanImports) { + m_shouldScanImports = true; + scan = true; + } + } + if (scan) + updateImportPaths(); + } + + return result; } @@ -939,24 +954,28 @@ void ModelManager::importScan(QFutureInterface<void> &future, QVector<ScanItem> pathsToScan; pathsToScan.reserve(paths.size()); - foreach (const QString &path, paths) { - QString cPath = QDir::cleanPath(path); - if (modelManager->m_scannedPaths.contains(cPath)) - continue; - pathsToScan.append(ScanItem(cPath)); + { + QMutexLocker l(&modelManager->m_mutex); + foreach (const QString &path, paths) { + QString cPath = QDir::cleanPath(path); + if (modelManager->m_scannedPaths.contains(cPath)) + continue; + pathsToScan.append(ScanItem(cPath)); + modelManager->m_scannedPaths.insert(cPath); + } } const int maxScanDepth = 5; int progressRange = pathsToScan.size() * (1 << (2 + maxScanDepth)); int totalWork(progressRange), workDone(0); future.setProgressRange(0, progressRange); // update max length while iterating? const bool libOnly = true; // FIXME remove when tested more + const Snapshot snapshot = modelManager->snapshot(); while (!pathsToScan.isEmpty() && !future.isCanceled()) { ScanItem toScan = pathsToScan.last(); pathsToScan.pop_back(); int pathBudget = (maxScanDepth + 2 - toScan.depth); if (!scannedPaths.contains(toScan.path)) { QStringList importedFiles; - const Snapshot snapshot = modelManager->snapshot(); if (!findNewQmlLibraryInPath(toScan.path, snapshot, modelManager, &importedFiles, &scannedPaths, &newLibraries, true) && !libOnly && snapshot.documentsInDirectory(toScan.path).isEmpty()) @@ -989,6 +1008,12 @@ void ModelManager::importScan(QFutureInterface<void> &future, future.setProgressValue(progressRange * workDone / totalWork); } future.setProgressValue(progressRange); + if (future.isCanceled()) { + // assume no work has been done + QMutexLocker l(&modelManager->m_mutex); + foreach (const QString &path, paths) + modelManager->m_scannedPaths.remove(path); + } } // Check whether fileMimeType is the same or extends knownMimeType @@ -1103,10 +1128,16 @@ void ModelManager::updateImportPaths() updateSourceFiles(importedFiles, true); + if (!m_shouldScanImports) + return; QStringList pathToScan; - foreach (QString importPath, allImportPaths) - if (!m_scannedPaths.contains(importPath)) - pathToScan.append(importPath); + { + QMutexLocker l(&m_mutex); + foreach (QString importPath, allImportPaths) + if (!m_scannedPaths.contains(importPath)) { + pathToScan.append(importPath); + } + } if (pathToScan.count() > 1) { QFuture<void> result = QtConcurrent::run(&ModelManager::importScan, diff --git a/src/plugins/qmljstools/qmljsmodelmanager.h b/src/plugins/qmljstools/qmljsmodelmanager.h index 6d30d536e2..13c291e77f 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.h +++ b/src/plugins/qmljstools/qmljsmodelmanager.h @@ -179,6 +179,7 @@ private: QmlJS::QmlLanguageBundles m_activeBundles; QmlJS::QmlLanguageBundles m_extendedBundles; QmlJS::ViewerContext m_vContext; + bool m_shouldScanImports; QSet<QString> m_scannedPaths; QTimer *m_updateCppQmlTypesTimer; diff --git a/src/plugins/qmlprofiler/canvas/canvas.pri b/src/plugins/qmlprofiler/canvas/canvas.pri deleted file mode 100644 index 2960e94527..0000000000 --- a/src/plugins/qmlprofiler/canvas/canvas.pri +++ /dev/null @@ -1,9 +0,0 @@ -HEADERS += $$PWD/qdeclarativecontext2d_p.h \ - $$PWD/qdeclarativecanvas_p.h \ - $$PWD/qmlprofilercanvas.h \ - $$PWD/qdeclarativecanvastimer_p.h - -SOURCES += $$PWD/qdeclarativecontext2d.cpp \ - $$PWD/qdeclarativecanvas.cpp \ - $$PWD/qmlprofilercanvas.cpp \ - $$PWD/qdeclarativecanvastimer.cpp diff --git a/src/plugins/qmlprofiler/canvas/qdeclarativecanvas.cpp b/src/plugins/qmlprofiler/canvas/qdeclarativecanvas.cpp deleted file mode 100644 index 4611d7096b..0000000000 --- a/src/plugins/qmlprofiler/canvas/qdeclarativecanvas.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "qdeclarativecanvas_p.h" -#include "qdeclarativecanvastimer_p.h" -#include "qdeclarativecontext2d_p.h" - -#include <qpainter.h> - -QT_BEGIN_NAMESPACE - -Canvas::Canvas(QQuickPaintedItem *parent) - : QQuickPaintedItem(parent), - m_context(new Context2D(this)), - m_canvasWidth(0), - m_canvasHeight(0), - m_fillMode(Canvas::Stretch), - m_color(Qt::white) -{ -} - - -void Canvas::componentComplete() -{ - if (m_canvasWidth == 0 && m_canvasHeight == 0) - m_context->setSize(width(), height()); - else - m_context->setSize(m_canvasWidth, m_canvasHeight); - - connect(m_context, SIGNAL(changed()), this, SLOT(requestPaint())); - emit init(); - QQuickItem::componentComplete(); -} - -void Canvas::paint(QPainter *painter) -{ - m_context->setInPaint(true); - emit paint(); - - bool oldAA = painter->testRenderHint(QPainter::Antialiasing); - bool oldSmooth = painter->testRenderHint(QPainter::SmoothPixmapTransform); - if (smooth()) - painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, smooth()); - - if (m_context->pixmap().isNull()) { - painter->fillRect(0, 0, width(), height(), m_color); - } else if (width() != m_context->pixmap().width() || height() != m_context->pixmap().height()) { - if (m_fillMode>= Tile) { - if (m_fillMode== Tile) { - painter->drawTiledPixmap(QRectF(0,0,width(),height()), m_context->pixmap()); - } else { - qreal widthScale = width() / qreal(m_context->pixmap().width()); - qreal heightScale = height() / qreal(m_context->pixmap().height()); - - QTransform scale; - if (m_fillMode== TileVertically) { - scale.scale(widthScale, 1.0); - QTransform old = painter->transform(); - painter->setWorldTransform(scale * old); - painter->drawTiledPixmap(QRectF(0,0,m_context->pixmap().width(),height()), m_context->pixmap()); - painter->setWorldTransform(old); - } else { - scale.scale(1.0, heightScale); - QTransform old = painter->transform(); - painter->setWorldTransform(scale * old); - painter->drawTiledPixmap(QRectF(0,0,width(),m_context->pixmap().height()), m_context->pixmap()); - painter->setWorldTransform(old); - } - } - } else { - qreal widthScale = width() / qreal(m_context->pixmap().width()); - qreal heightScale = height() / qreal(m_context->pixmap().height()); - - QTransform scale; - - if (m_fillMode== PreserveAspectFit) { - if (widthScale <= heightScale) { - heightScale = widthScale; - scale.translate(0, (height() - heightScale * m_context->pixmap().height()) / 2); - } else if (heightScale < widthScale) { - widthScale = heightScale; - scale.translate((width() - widthScale * m_context->pixmap().width()) / 2, 0); - } - } else if (m_fillMode== PreserveAspectCrop) { - if (widthScale < heightScale) { - widthScale = heightScale; - scale.translate((width() - widthScale * m_context->pixmap().width()) / 2, 0); - } else if (heightScale < widthScale) { - heightScale = widthScale; - scale.translate(0, (height() - heightScale * m_context->pixmap().height()) / 2); - } - } - if (clip()) { - painter->save(); - painter->setClipRect(boundingRect(), Qt::IntersectClip); - } - scale.scale(widthScale, heightScale); - QTransform old = painter->transform(); - painter->setWorldTransform(scale * old); - painter->drawPixmap(0, 0, m_context->pixmap()); - painter->setWorldTransform(old); - if (clip()) - painter->restore(); - } - } else { - painter->drawPixmap(0, 0, m_context->pixmap()); - } - - if (smooth()) { - painter->setRenderHint(QPainter::Antialiasing, oldAA); - painter->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth); - } - m_context->setInPaint(false); -} - -Context2D *Canvas::getContext(const QString &contextId) -{ - if (contextId == QLatin1String("2d")) - return m_context; - qDebug("Canvas:requesting unsupported context"); - return 0; -} - -void Canvas::requestPaint() -{ - update(); -} - -void Canvas::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - if (m_canvasWidth == 0 && m_canvasHeight == 0 - && newGeometry.width() > 0 && newGeometry.height() > 0) { - m_context->setSize(width(), height()); - } - QQuickItem::geometryChanged(newGeometry, oldGeometry); -} - -void Canvas::setCanvasWidth(int newWidth) -{ - if (m_canvasWidth != newWidth) { - m_canvasWidth = newWidth; - m_context->setSize(m_canvasWidth, m_canvasHeight); - emit canvasWidthChanged(); - } -} - -void Canvas::setCanvasHeight(int newHeight) -{ - if (m_canvasHeight != newHeight) { - m_canvasHeight = newHeight; - m_context->setSize(m_canvasWidth, m_canvasHeight); - emit canvasHeightChanged(); - } -} - -void Canvas::setFillMode(FillMode mode) -{ - if (m_fillMode == mode) - return; - - m_fillMode = mode; - update(); - emit fillModeChanged(); -} - -QColor Canvas::color() -{ - return m_color; -} - -void Canvas::setColor(const QColor &color) -{ - if (m_color !=color) { - m_color = color; - colorChanged(); - } -} - -Canvas::FillMode Canvas::fillMode() const -{ - return m_fillMode; -} - -bool Canvas::save(const QString &filename) const -{ - return m_context->pixmap().save(filename); -} - -CanvasImage *Canvas::toImage() const -{ - return new CanvasImage(m_context->pixmap()); -} - -void Canvas::setTimeout(const QJSValue &handler, long timeout) -{ - if (handler.isCallable()) - CanvasTimer::createTimer(this, handler, timeout, true); -} - -void Canvas::setInterval(const QJSValue &handler, long interval) -{ - if (handler.isCallable()) - CanvasTimer::createTimer(this, handler, interval, false); -} - -void Canvas::clearTimeout(const QJSValue &handler) -{ - CanvasTimer::removeTimer(handler); -} - -void Canvas::clearInterval(const QJSValue &handler) -{ - CanvasTimer::removeTimer(handler); -} - -QT_END_NAMESPACE diff --git a/src/plugins/qmlprofiler/canvas/qdeclarativecanvas_p.h b/src/plugins/qmlprofiler/canvas/qdeclarativecanvas_p.h deleted file mode 100644 index 3f4fd8b0dd..0000000000 --- a/src/plugins/qmlprofiler/canvas/qdeclarativecanvas_p.h +++ /dev/null @@ -1,107 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#ifndef QDECLARATIVECANVAS_P_H -#define QDECLARATIVECANVAS_P_H - -#include <QQuickPaintedItem> - -#include "qdeclarativecontext2d_p.h" -#include "qdeclarativecanvastimer_p.h" - -QT_BEGIN_NAMESPACE - -class Canvas : public QQuickPaintedItem -{ - Q_OBJECT - - Q_ENUMS(FillMode) - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged); - Q_PROPERTY(int canvasWidth READ canvasWidth WRITE setCanvasWidth NOTIFY canvasWidthChanged); - Q_PROPERTY(int canvasHeight READ canvasHeight WRITE setCanvasHeight NOTIFY canvasHeightChanged); - Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) - -public: - Canvas(QQuickPaintedItem *parent = 0); - enum FillMode { Stretch, PreserveAspectFit, PreserveAspectCrop, Tile, TileVertically, TileHorizontally }; - - - void paint(QPainter *); - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - void setCanvasWidth(int newWidth); - int canvasWidth() {return m_canvasWidth;} - - void setCanvasHeight(int canvasHeight); - int canvasHeight() {return m_canvasHeight;} - - void componentComplete(); - - -public Q_SLOTS: - Context2D *getContext(const QString & = QLatin1String("2d")); - void requestPaint(); - - FillMode fillMode() const; - void setFillMode(FillMode); - - QColor color(); - void setColor(const QColor &); - - // Save current canvas to disk - bool save(const QString& filename) const; - - // Timers - void setInterval(const QJSValue &handler, long timeout); - void setTimeout(const QJSValue &handler, long timeout); - void clearInterval(const QJSValue &handler); - void clearTimeout(const QJSValue &handler); - -Q_SIGNALS: - void fillModeChanged(); - void canvasWidthChanged(); - void canvasHeightChanged(); - void colorChanged(); - void init(); - void paint(); - -private: - // Return canvas contents as a drawable image - CanvasImage *toImage() const; - Context2D *m_context; - int m_canvasWidth; - int m_canvasHeight; - FillMode m_fillMode; - QColor m_color; - - friend class Context2D; -}; - -QT_END_NAMESPACE - -#endif //QDECLARATIVECANVAS_P_H diff --git a/src/plugins/qmlprofiler/canvas/qdeclarativecontext2d.cpp b/src/plugins/qmlprofiler/canvas/qdeclarativecontext2d.cpp deleted file mode 100644 index f006657bfc..0000000000 --- a/src/plugins/qmlprofiler/canvas/qdeclarativecontext2d.cpp +++ /dev/null @@ -1,1134 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "qdeclarativecontext2d_p.h" - -#include "qdeclarativecanvas_p.h" - -#include <qdebug.h> -#include <math.h> - -#include <qgraphicsitem.h> -#include <qapplication.h> -#include <qgraphicseffect.h> - -#include <QImage> -#include <QWidget> - -QT_BEGIN_NAMESPACE - -static const double Q_PI = 3.14159265358979323846; // pi - -class CustomDropShadowEffect : public QGraphicsDropShadowEffect -{ -public: - void draw(QPainter *painter) { QGraphicsDropShadowEffect::draw(painter);} - void drawSource(QPainter *painter) { QGraphicsDropShadowEffect::drawSource(painter);} -}; - -// Note, this is exported but in a private header as qtopengl depends on it. -// But it really should be considered private API -void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0); -void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); - -#define DEGREES(t) ((t) * 180.0 / Q_PI) - -#define qClamp(val, min, max) qMin(qMax(val, min), max) -static QList<qreal> parseNumbersList(QString::const_iterator &itr) -{ - QList<qreal> points; - QString temp; - while ((*itr).isSpace()) - ++itr; - while ((*itr).isNumber() || - (*itr) == QLatin1Char('-') || (*itr) == QLatin1Char('+') || (*itr) == QLatin1Char('.')) { - temp.clear(); - - if ((*itr) == QLatin1Char('-')) - temp += *itr++; - else if ((*itr) == QLatin1Char('+')) - temp += *itr++; - while ((*itr).isDigit()) - temp += *itr++; - if ((*itr) == QLatin1Char('.')) - temp += *itr++; - while ((*itr).isDigit()) - temp += *itr++; - while ((*itr).isSpace()) - ++itr; - if ((*itr) == QLatin1Char(',')) - ++itr; - points.append(temp.toDouble()); - //eat spaces - while ((*itr).isSpace()) - ++itr; - } - - return points; -} - -QColor colorFromString(const QString &name) -{ - QString::const_iterator itr = name.constBegin(); - QList<qreal> compo; - if (name.startsWith(QLatin1String("rgba("))) { - ++itr; ++itr; ++itr; ++itr; ++itr; - compo = parseNumbersList(itr); - if (compo.size() != 4) - return QColor(); - //alpha seems to be always between 0-1 - compo[3] *= 255; - return QColor((int)compo[0], (int)compo[1], - (int)compo[2], (int)compo[3]); - } else if (name.startsWith(QLatin1String("rgb("))) { - ++itr; ++itr; ++itr; ++itr; - compo = parseNumbersList(itr); - if (compo.size() != 3) - return QColor(); - return QColor((int)qClamp(compo[0], qreal(0), qreal(255)), - (int)qClamp(compo[1], qreal(0), qreal(255)), - (int)qClamp(compo[2], qreal(0), qreal(255))); - } else if (name.startsWith(QLatin1String("hsla("))) { - ++itr; ++itr; ++itr; ++itr; ++itr; - compo = parseNumbersList(itr); - if (compo.size() != 4) - return QColor(); - return QColor::fromHslF(compo[0], compo[1], - compo[2], compo[3]); - } else if (name.startsWith(QLatin1String("hsl("))) { - ++itr; ++itr; ++itr; ++itr; ++itr; - compo = parseNumbersList(itr); - if (compo.size() != 3) - return QColor(); - return QColor::fromHslF(compo[0], compo[1], - compo[2]); - } else { - //QRgb color; - //CSSParser::parseColor(name, color); - return QColor(name); - } -} - - -static QPainter::CompositionMode compositeOperatorFromString(const QString &compositeOperator) -{ - if (compositeOperator == QLatin1String("source-over")) - return QPainter::CompositionMode_SourceOver; - else if (compositeOperator == QLatin1String("source-out")) - return QPainter::CompositionMode_SourceOut; - else if (compositeOperator == QLatin1String("source-in")) - return QPainter::CompositionMode_SourceIn; - else if (compositeOperator == QLatin1String("source-atop")) - return QPainter::CompositionMode_SourceAtop; - else if (compositeOperator == QLatin1String("destination-atop")) - return QPainter::CompositionMode_DestinationAtop; - else if (compositeOperator == QLatin1String("destination-in")) - return QPainter::CompositionMode_DestinationIn; - else if (compositeOperator == QLatin1String("destination-out")) - return QPainter::CompositionMode_DestinationOut; - else if (compositeOperator == QLatin1String("destination-over")) - return QPainter::CompositionMode_DestinationOver; - else if (compositeOperator == QLatin1String("darker")) - return QPainter::CompositionMode_SourceOver; - else if (compositeOperator == QLatin1String("lighter")) - return QPainter::CompositionMode_SourceOver; - else if (compositeOperator == QLatin1String("copy")) - return QPainter::CompositionMode_Source; - else if (compositeOperator == QLatin1String("xor")) - return QPainter::CompositionMode_Xor; - - return QPainter::CompositionMode_SourceOver; -} - -static QString compositeOperatorToString(QPainter::CompositionMode op) -{ - switch (op) { - case QPainter::CompositionMode_SourceOver: - return QLatin1String("source-over"); - case QPainter::CompositionMode_DestinationOver: - return QLatin1String("destination-over"); - case QPainter::CompositionMode_Clear: - return QLatin1String("clear"); - case QPainter::CompositionMode_Source: - return QLatin1String("source"); - case QPainter::CompositionMode_Destination: - return QLatin1String("destination"); - case QPainter::CompositionMode_SourceIn: - return QLatin1String("source-in"); - case QPainter::CompositionMode_DestinationIn: - return QLatin1String("destination-in"); - case QPainter::CompositionMode_SourceOut: - return QLatin1String("source-out"); - case QPainter::CompositionMode_DestinationOut: - return QLatin1String("destination-out"); - case QPainter::CompositionMode_SourceAtop: - return QLatin1String("source-atop"); - case QPainter::CompositionMode_DestinationAtop: - return QLatin1String("destination-atop"); - case QPainter::CompositionMode_Xor: - return QLatin1String("xor"); - case QPainter::CompositionMode_Plus: - return QLatin1String("plus"); - case QPainter::CompositionMode_Multiply: - return QLatin1String("multiply"); - case QPainter::CompositionMode_Screen: - return QLatin1String("screen"); - case QPainter::CompositionMode_Overlay: - return QLatin1String("overlay"); - case QPainter::CompositionMode_Darken: - return QLatin1String("darken"); - case QPainter::CompositionMode_Lighten: - return QLatin1String("lighten"); - case QPainter::CompositionMode_ColorDodge: - return QLatin1String("color-dodge"); - case QPainter::CompositionMode_ColorBurn: - return QLatin1String("color-burn"); - case QPainter::CompositionMode_HardLight: - return QLatin1String("hard-light"); - case QPainter::CompositionMode_SoftLight: - return QLatin1String("soft-light"); - case QPainter::CompositionMode_Difference: - return QLatin1String("difference"); - case QPainter::CompositionMode_Exclusion: - return QLatin1String("exclusion"); - default: - break; - } - return QString(); -} - -void Context2D::save() -{ - m_stateStack.push(m_state); -} - - -void Context2D::restore() -{ - if (!m_stateStack.isEmpty()) { - m_state = m_stateStack.pop(); - m_state.flags = AllIsFullOfDirt; - } -} - - -void Context2D::scale(qreal x, qreal y) -{ - m_state.matrix.scale(x, y); - m_state.flags |= DirtyTransformationMatrix; -} - - -void Context2D::rotate(qreal angle) -{ - m_state.matrix.rotate(DEGREES(angle)); - m_state.flags |= DirtyTransformationMatrix; -} - - -void Context2D::translate(qreal x, qreal y) -{ - m_state.matrix.translate(x, y); - m_state.flags |= DirtyTransformationMatrix; -} - - -void Context2D::transform(qreal m11, qreal m12, qreal m21, qreal m22, - qreal dx, qreal dy) -{ - QMatrix mat(m11, m12, - m21, m22, - dx, dy); - m_state.matrix *= mat; - m_state.flags |= DirtyTransformationMatrix; -} - - -void Context2D::setTransform(qreal m11, qreal m12, qreal m21, qreal m22, - qreal dx, qreal dy) -{ - QMatrix mat(m11, m12, - m21, m22, - dx, dy); - m_state.matrix = mat; - m_state.flags |= DirtyTransformationMatrix; -} - - -QString Context2D::globalCompositeOperation() const -{ - return compositeOperatorToString(m_state.globalCompositeOperation); -} - -void Context2D::setGlobalCompositeOperation(const QString &op) -{ - QPainter::CompositionMode mode = - compositeOperatorFromString(op); - m_state.globalCompositeOperation = mode; - m_state.flags |= DirtyGlobalCompositeOperation; -} - -QVariant Context2D::strokeStyle() const -{ - return m_state.strokeStyle; -} - -void Context2D::setStrokeStyle(const QVariant &style) -{ - CanvasGradient * gradient= qobject_cast<CanvasGradient*>(style.value<QObject*>()); - if (gradient) { - m_state.strokeStyle = gradient->value(); - } else { - QColor color = colorFromString(style.toString()); - m_state.strokeStyle = color; - } - m_state.flags |= DirtyStrokeStyle; -} - -QVariant Context2D::fillStyle() const -{ - return m_state.fillStyle; -} - -void Context2D::setFillStyle(const QVariant &style) -{ - CanvasGradient * gradient= qobject_cast<CanvasGradient*>(style.value<QObject*>()); - if (gradient) { - m_state.fillStyle = gradient->value(); - } else { - QColor color = colorFromString(style.toString()); - m_state.fillStyle = color; - } - m_state.flags |= DirtyFillStyle; -} - -qreal Context2D::globalAlpha() const -{ - return m_state.globalAlpha; -} - -void Context2D::setGlobalAlpha(qreal alpha) -{ - m_state.globalAlpha = alpha; - m_state.flags |= DirtyGlobalAlpha; -} - -CanvasImage *Context2D::createImage(const QString &url) -{ - return new CanvasImage(url); -} - -CanvasGradient *Context2D::createLinearGradient(qreal x0, qreal y0, - qreal x1, qreal y1) -{ - QLinearGradient g(x0, y0, x1, y1); - return new CanvasGradient(g); -} - - -CanvasGradient *Context2D::createRadialGradient(qreal x0, qreal y0, - qreal r0, qreal x1, - qreal y1, qreal r1) -{ - QRadialGradient g(QPointF(x1, y1), r0+r1, QPointF(x0, y0)); - return new CanvasGradient(g); -} - -qreal Context2D::lineWidth() const -{ - return m_state.lineWidth; -} - -void Context2D::setLineWidth(qreal w) -{ - m_state.lineWidth = w; - m_state.flags |= DirtyLineWidth; -} - -QString Context2D::lineCap() const -{ - switch (m_state.lineCap) { - case Qt::FlatCap: - return QLatin1String("butt"); - case Qt::SquareCap: - return QLatin1String("square"); - case Qt::RoundCap: - return QLatin1String("round"); - default: ; - } - return QString(); -} - -void Context2D::setLineCap(const QString &capString) -{ - Qt::PenCapStyle style; - if (capString == QLatin1String("round")) - style = Qt::RoundCap; - else if (capString == QLatin1String("square")) - style = Qt::SquareCap; - else //if (capString == QLatin1String("butt")) - style = Qt::FlatCap; - m_state.lineCap = style; - m_state.flags |= DirtyLineCap; -} - -QString Context2D::lineJoin() const -{ - switch (m_state.lineJoin) { - case Qt::RoundJoin: - return QLatin1String("round"); - case Qt::BevelJoin: - return QLatin1String("bevel"); - case Qt::MiterJoin: - return QLatin1String("miter"); - default: ; - } - return QString(); -} - -void Context2D::setLineJoin(const QString &joinString) -{ - Qt::PenJoinStyle style; - if (joinString == QLatin1String("round")) - style = Qt::RoundJoin; - else if (joinString == QLatin1String("bevel")) - style = Qt::BevelJoin; - else //if (joinString == "miter") - style = Qt::MiterJoin; - m_state.lineJoin = style; - m_state.flags |= DirtyLineJoin; -} - -qreal Context2D::miterLimit() const -{ - return m_state.miterLimit; -} - -void Context2D::setMiterLimit(qreal m) -{ - m_state.miterLimit = m; - m_state.flags |= DirtyMiterLimit; -} - -void Context2D::setShadowOffsetX(qreal x) -{ - if (m_state.shadowOffsetX == x) - return; - m_state.shadowOffsetX = x; - updateShadowBuffer(); - if (m_painter.device() == &m_shadowbuffer && m_state.shadowBlur>0) - endPainting(); - m_state.flags |= DirtyShadowOffsetX; -} - -const QList<Context2D::MouseArea> &Context2D::mouseAreas() const -{ - return m_mouseAreas; -} - -void Context2D::updateShadowBuffer() { - if (m_shadowbuffer.isNull() || m_shadowbuffer.width() != m_width+m_state.shadowOffsetX || - m_shadowbuffer.height() != m_height+m_state.shadowOffsetY) { - m_shadowbuffer = QImage(m_width+m_state.shadowOffsetX, m_height+m_state.shadowOffsetY, QImage::Format_ARGB32); - m_shadowbuffer.fill(Qt::transparent); - } -} - -void Context2D::setShadowOffsetY(qreal y) -{ - if (m_state.shadowOffsetY == y) - return; - m_state.shadowOffsetY = y; - updateShadowBuffer(); - if (m_painter.device() == &m_shadowbuffer && m_state.shadowBlur>0) - endPainting(); - - m_state.flags |= DirtyShadowOffsetY; -} - -void Context2D::setShadowBlur(qreal b) -{ - if (m_state.shadowBlur == b) - return; - m_state.shadowBlur = b; - updateShadowBuffer(); - if (m_painter.device() == &m_shadowbuffer && m_state.shadowBlur>0) - endPainting(); - m_state.flags |= DirtyShadowBlur; -} - -void Context2D::setShadowColor(const QString &str) -{ - m_state.shadowColor = colorFromString(str); - if (m_painter.device() == &m_shadowbuffer && m_state.shadowBlur>0) - endPainting(); - m_state.flags |= DirtyShadowColor; -} - -QString Context2D::textBaseline() -{ - switch (m_state.textBaseline) { - case Context2D::Alphabetic: - return QLatin1String("alphabetic"); - case Context2D::Hanging: - return QLatin1String("hanging"); - case Context2D::Bottom: - return QLatin1String("bottom"); - case Context2D::Top: - return QLatin1String("top"); - case Context2D::Middle: - return QLatin1String("middle"); - default: - Q_ASSERT("invalid value"); - return QLatin1String("start"); - } -} - -void Context2D::setTextBaseline(const QString &baseline) -{ - if (baseline==QLatin1String("alphabetic")) { - m_state.textBaseline = Context2D::Alphabetic; - } else if (baseline == QLatin1String("hanging")) { - m_state.textBaseline = Context2D::Hanging; - } else if (baseline == QLatin1String("top")) { - m_state.textBaseline = Context2D::Top; - } else if (baseline == QLatin1String("bottom")) { - m_state.textBaseline = Context2D::Bottom; - } else if (baseline == QLatin1String("middle")) { - m_state.textBaseline = Context2D::Middle; - } else { - m_state.textBaseline = Context2D::Alphabetic; - qWarning() << (QLatin1String("Context2D: invalid baseline:") + baseline); - } - m_state.flags |= DirtyTextBaseline; -} - -QString Context2D::textAlign() -{ - switch (m_state.textAlign) { - case Context2D::Left: - return QLatin1String("left"); - case Context2D::Right: - return QLatin1String("right"); - case Context2D::Center: - return QLatin1String("center"); - case Context2D::Start: - return QLatin1String("start"); - case Context2D::End: - return QLatin1String("end"); - default: - Q_ASSERT("invalid value"); - qWarning() << ("Context2D::invalid textAlign"); - return QLatin1String("start"); - } -} - -void Context2D::setTextAlign(const QString &baseline) -{ - if (baseline==QLatin1String("start")) { - m_state.textAlign = Context2D::Start; - } else if (baseline == QLatin1String("end")) { - m_state.textAlign = Context2D::End; - } else if (baseline == QLatin1String("left")) { - m_state.textAlign = Context2D::Left; - } else if (baseline == QLatin1String("right")) { - m_state.textAlign = Context2D::Right; - } else if (baseline == QLatin1String("center")) { - m_state.textAlign = Context2D::Center; - } else { - m_state.textAlign= Context2D::Start; - qWarning("Context2D: invalid text align"); - } - // ### alphabetic, ideographic, hanging - m_state.flags |= DirtyTextBaseline; -} - -void Context2D::setFont(const QString &fontString) -{ - QFont font; - // ### this is simplified and incomplete - QStringList tokens = fontString.split(QLatin1Char(QLatin1Char(' '))); - foreach (const QString &token, tokens) { - if (token == QLatin1String("italic")) { - font.setItalic(true); - } else if (token == QLatin1String("bold")) { - font.setBold(true); - } else if (token.endsWith(QLatin1String("px"))) { - QString number = token; - number.remove(QLatin1String("px")); -#ifdef Q_OS_MACX - // compensating the extra antialias space with bigger fonts - // this class is only used by the QML Profiler - // not much harm can be inflicted by this dirty hack - font.setPointSizeF(number.trimmed().toFloat()*4.0f/3.0f); -#else - font.setPointSizeF(number.trimmed().toFloat()); -#endif - } else { - font.setFamily(token); - } - } - m_state.font = font; - m_state.flags |= DirtyFont; -} - -QString Context2D::font() -{ - return m_state.font.toString(); -} - -qreal Context2D::shadowOffsetX() const -{ - return m_state.shadowOffsetX; -} - -qreal Context2D::shadowOffsetY() const -{ - return m_state.shadowOffsetY; -} - - -qreal Context2D::shadowBlur() const -{ - return m_state.shadowBlur; -} - - -QString Context2D::shadowColor() const -{ - return m_state.shadowColor.name(); -} - - -void Context2D::clearRect(qreal x, qreal y, qreal w, qreal h) -{ - beginPainting(); - m_painter.save(); - m_painter.setMatrix(worldMatrix(), false); - m_painter.setCompositionMode(QPainter::CompositionMode_Source); - QColor fillColor = parent()->property("color").value<QColor>(); - - m_painter.fillRect(QRectF(x, y, w, h), fillColor); - m_painter.restore(); - scheduleChange(); -} - -void Context2D::fillRect(qreal x, qreal y, qreal w, qreal h) -{ - beginPainting(); - m_painter.save(); - m_painter.setMatrix(worldMatrix(), false); - m_painter.fillRect(QRectF(x, y, w, h), m_painter.brush()); - m_painter.restore(); - scheduleChange(); -} - -int Context2D::baseLineOffset(Context2D::TextBaseLine value, const QFontMetrics &metrics) -{ - int offset = 0; - switch (value) { - case Context2D::Top: - break; - case Context2D::Alphabetic: - case Context2D::Middle: - case Context2D::Hanging: - offset = metrics.ascent(); - break; - case Context2D::Bottom: - offset = metrics.height(); - break; - } - return offset; -} - -int Context2D::textAlignOffset(Context2D::TextAlign value, const QFontMetrics &metrics, const QString &text) -{ - int offset = 0; - if (value == Context2D::Start) - value = qApp->layoutDirection() == Qt::LeftToRight ? Context2D::Left : Context2D::Right; - else if (value == Context2D::End) - value = qApp->layoutDirection() == Qt::LeftToRight ? Context2D::Right: Context2D::Left; - switch (value) { - case Context2D::Center: - offset = metrics.width(text)/2; - break; - case Context2D::Right: - offset = metrics.width(text); - case Context2D::Left: - default: - break; - } - return offset; -} - -void Context2D::fillText(const QString &text, qreal x, qreal y) -{ - beginPainting(); - m_painter.save(); - m_painter.setPen(QPen(m_state.fillStyle, m_state.lineWidth)); - m_painter.setMatrix(worldMatrix(), false); - QFont font; - font.setBold(true); - m_painter.setFont(m_state.font); - int yoffset = baseLineOffset(m_state.textBaseline, m_painter.fontMetrics()); - int xoffset = textAlignOffset(m_state.textAlign, m_painter.fontMetrics(), text); - QTextOption opt; // Adjust baseLine etc - m_painter.drawText(QRectF(x-xoffset, y-yoffset, QWIDGETSIZE_MAX, m_painter.fontMetrics().height()), text, opt); - m_painter.restore(); - endPainting(); - scheduleChange(); -} - -void Context2D::strokeText(const QString &text, qreal x, qreal y) -{ - beginPainting(); - m_painter.save(); - m_painter.setPen(QPen(m_state.fillStyle,0)); - m_painter.setMatrix(worldMatrix(), false); - - QPainterPath textPath; - QFont font = m_state.font; - font.setStyleStrategy(QFont::ForceOutline); - m_painter.setFont(font); - const QFontMetrics &metrics = m_painter.fontMetrics(); - int yoffset = baseLineOffset(m_state.textBaseline, metrics); - int xoffset = textAlignOffset(m_state.textAlign, metrics, text); - textPath.addText(x-xoffset, y-yoffset+metrics.ascent(), font, text); - m_painter.strokePath(textPath, QPen(m_state.fillStyle, m_state.lineWidth)); - m_painter.restore(); - endPainting(); - scheduleChange(); -} - -void Context2D::strokeRect(qreal x, qreal y, qreal w, qreal h) -{ - QPainterPath path; - path.addRect(x, y, w, h); - beginPainting(); - m_painter.save(); - m_painter.setMatrix(worldMatrix(), false); - m_painter.strokePath(path, m_painter.pen()); - m_painter.restore(); - scheduleChange(); -} - -void Context2D::mouseArea(qreal x, qreal y, qreal w, qreal h, const QJSValue &callback, - const QJSValue &data) -{ - MouseArea a = { callback, data, QRectF(x, y, w, h), m_state.matrix }; - m_mouseAreas << a; -} - -void Context2D::beginPath() -{ - m_path = QPainterPath(); -} - - -void Context2D::closePath() -{ - m_path.closeSubpath(); -} - - -void Context2D::moveTo(qreal x, qreal y) -{ - QPointF pt = worldMatrix().map(QPointF(x, y)); - m_path.moveTo(pt); -} - - -void Context2D::lineTo(qreal x, qreal y) -{ - QPointF pt = worldMatrix().map(QPointF(x, y)); - m_path.lineTo(pt); -} - - -void Context2D::quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y) -{ - QPointF cp = worldMatrix().map(QPointF(cpx, cpy)); - QPointF xy = worldMatrix().map(QPointF(x, y)); - m_path.quadTo(cp, xy); -} - - -void Context2D::bezierCurveTo(qreal cp1x, qreal cp1y, - qreal cp2x, qreal cp2y, qreal x, qreal y) -{ - QPointF cp1 = worldMatrix().map(QPointF(cp1x, cp1y)); - QPointF cp2 = worldMatrix().map(QPointF(cp2x, cp2y)); - QPointF end = worldMatrix().map(QPointF(x, y)); - m_path.cubicTo(cp1, cp2, end); -} - - -void Context2D::arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius) -{ - //FIXME: this is surely busted - QPointF st = worldMatrix().map(QPointF(x1, y1)); - QPointF end = worldMatrix().map(QPointF(x2, y2)); - m_path.arcTo(st.x(), st.y(), - end.x()-st.x(), end.y()-st.y(), - radius, 90); -} - - -void Context2D::rect(qreal x, qreal y, qreal w, qreal h) -{ - QPainterPath path; path.addRect(x, y, w, h); - path = worldMatrix().map(path); - m_path.addPath(path); -} - -void Context2D::arc(qreal xc, qreal yc, qreal radius, - qreal sar, qreal ear, - bool anticlockwise) -{ - //### HACK - // In Qt we don't switch the coordinate system for degrees - // and still use the 0,0 as bottom left for degrees so we need - // to switch - sar = -sar; - ear = -ear; - anticlockwise = !anticlockwise; - //end hack - - float sa = DEGREES(sar); - float ea = DEGREES(ear); - - double span = 0; - - double xs = xc - radius; - double ys = yc - radius; - double width = radius*2; - double height = radius*2; - - if (!anticlockwise && (ea < sa)) - span += 360; - else if (anticlockwise && (sa < ea)) - span -= 360; - - //### this is also due to switched coordinate system - // we would end up with a 0 span instead of 360 - if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) && - qFuzzyCompare(qAbs(span), 360))) { - span += ea - sa; - } - - QPainterPath path; - path.moveTo(QPointF(xc + radius * cos(sar), - yc - radius * sin(sar))); - - path.arcTo(xs, ys, width, height, sa, span); - path = worldMatrix().map(path); - m_path.addPath(path); -} - - -void Context2D::fill() -{ - beginPainting(); - m_painter.fillPath(m_path, m_painter.brush()); - scheduleChange(); -} - - -void Context2D::stroke() -{ - beginPainting(); - m_painter.save(); - m_painter.setMatrix(worldMatrix(), false); - QPainterPath tmp = worldMatrix().inverted().map(m_path); - m_painter.strokePath(tmp, m_painter.pen()); - m_painter.restore(); - scheduleChange(); -} - - -void Context2D::clip() -{ - m_state.clipPath = m_path; - m_state.flags |= DirtyClippingRegion; -} - - -bool Context2D::isPointInPath(qreal x, qreal y) const -{ - return m_path.contains(QPointF(x, y)); -} - - -ImageData Context2D::getImageData(qreal sx, qreal sy, qreal sw, qreal sh) -{ - Q_UNUSED(sx); - Q_UNUSED(sy); - Q_UNUSED(sw); - Q_UNUSED(sh); - return ImageData(); -} - - -void Context2D::putImageData(ImageData image, qreal dx, qreal dy) -{ - Q_UNUSED(image); - Q_UNUSED(dx); - Q_UNUSED(dy); -} - -Context2D::Context2D(QObject *parent) - : QObject(parent), m_changeTimerId(-1), m_width(0), m_height(0), m_inPaint(false) -{ - reset(); -} - -void Context2D::setupPainter() -{ - m_painter.setRenderHint(QPainter::Antialiasing, true); - if ((m_state.flags & DirtyClippingRegion) && !m_state.clipPath.isEmpty()) - m_painter.setClipPath(m_state.clipPath); - if (m_state.flags & DirtyFillStyle) - m_painter.setBrush(m_state.fillStyle); - if (m_state.flags & DirtyGlobalAlpha) - m_painter.setOpacity(m_state.globalAlpha); - if (m_state.flags & DirtyGlobalCompositeOperation) - m_painter.setCompositionMode(m_state.globalCompositeOperation); - if (m_state.flags & MDirtyPen) { - QPen pen = m_painter.pen(); - if (m_state.flags & DirtyStrokeStyle) - pen.setBrush(m_state.strokeStyle); - if (m_state.flags & DirtyLineWidth) - pen.setWidthF(m_state.lineWidth); - if (m_state.flags & DirtyLineCap) - pen.setCapStyle(m_state.lineCap); - if (m_state.flags & DirtyLineJoin) - pen.setJoinStyle(m_state.lineJoin); - if (m_state.flags & DirtyMiterLimit) - pen.setMiterLimit(m_state.miterLimit); - m_painter.setPen(pen); - } -} - -void Context2D::beginPainting() -{ - if (m_pixmap.width() != m_width || m_pixmap.height() != m_height) { - if (m_painter.isActive()) - m_painter.end(); - m_pixmap = QPixmap(m_width, m_height); - m_pixmap.fill(parent()->property("color").value<QColor>()); - } - - if (m_state.shadowBlur > 0 && m_painter.device() != &m_shadowbuffer) { - if (m_painter.isActive()) - m_painter.end(); - updateShadowBuffer(); - m_painter.begin(&m_shadowbuffer); - m_painter.setViewport(m_state.shadowOffsetX, - m_state.shadowOffsetY, - m_shadowbuffer.width(), - m_shadowbuffer.height()); - m_shadowbuffer.fill(Qt::transparent); - } - - if (!m_painter.isActive()) { - m_painter.begin(&m_pixmap); - m_painter.setRenderHint(QPainter::Antialiasing); - if (!m_state.clipPath.isEmpty()) - m_painter.setClipPath(m_state.clipPath); - m_painter.setBrush(m_state.fillStyle); - m_painter.setOpacity(m_state.globalAlpha); - QPen pen; - pen.setBrush(m_state.strokeStyle); - if (pen.style() == Qt::NoPen) - pen.setStyle(Qt::SolidLine); - pen.setCapStyle(m_state.lineCap); - pen.setJoinStyle(m_state.lineJoin); - pen.setWidthF(m_state.lineWidth); - pen.setMiterLimit(m_state.miterLimit); - m_painter.setPen(pen); - } else { - setupPainter(); - m_state.flags = 0; - } -} - -void Context2D::endPainting() -{ - if (m_state.shadowBlur > 0) { - QImage alphaChannel = m_shadowbuffer.alphaChannel(); - - qt_blurImage(alphaChannel, m_state.shadowBlur, false, 1); - - QRect imageRect = m_shadowbuffer.rect(); - - if (m_shadowColorIndexBuffer.isEmpty() || m_shadowColorBuffer != m_state.shadowColor) { - m_shadowColorIndexBuffer.clear(); - m_shadowColorBuffer = m_state.shadowColor; - - for (int i = 0; i < 256; ++i) { - m_shadowColorIndexBuffer << qRgba(qRound(255 * m_state.shadowColor.redF()), - qRound(255 * m_state.shadowColor.greenF()), - qRound(255 * m_state.shadowColor.blueF()), - i); - } - } - alphaChannel.setColorTable(m_shadowColorIndexBuffer); - - if (m_painter.isActive()) - m_painter.end(); - - m_painter.begin(&m_pixmap); - - // draw the blurred drop shadow... - m_painter.save(); - QTransform tf = m_painter.transform(); - m_painter.translate(0, imageRect.height()); - m_painter.rotate(-90); - m_painter.drawImage(0, 0, alphaChannel); - m_painter.setTransform(tf); - m_painter.restore(); - - // draw source - m_painter.drawImage(-m_state.shadowOffsetX, -m_state.shadowOffsetY, m_shadowbuffer.copy()); - m_painter.end(); - } -} - -void Context2D::clear() -{ - m_painter.fillRect(QRect(QPoint(0,0), size()), Qt::white); -} - -void Context2D::reset() -{ - m_stateStack.clear(); - m_state.matrix = QMatrix(); - m_state.clipPath = QPainterPath(); - m_state.strokeStyle = Qt::black; - m_state.fillStyle = Qt::black; - m_state.globalAlpha = 1.0; - m_state.lineWidth = 1; - m_state.lineCap = Qt::FlatCap; - m_state.lineJoin = Qt::MiterJoin; - m_state.miterLimit = 10; - m_state.shadowOffsetX = 0; - m_state.shadowOffsetY = 0; - m_state.shadowBlur = 0; - m_state.shadowColor = qRgba(0, 0, 0, 0); - m_state.globalCompositeOperation = QPainter::CompositionMode_SourceOver; - m_state.font = QFont(); - m_state.textAlign = Start; - m_state.textBaseline = Alphabetic; - m_state.flags = AllIsFullOfDirt; - m_mouseAreas.clear(); - clear(); -} - -void Context2D::drawImage(const QVariant &var, qreal sx, qreal sy, - qreal sw = 0, qreal sh = 0) -{ - CanvasImage *image = qobject_cast<CanvasImage*>(var.value<QObject*>()); - if (!image) { - Canvas *canvas = qobject_cast<Canvas*>(var.value<QObject*>()); - if (canvas) - image = canvas->toImage(); - } - if (image) { - beginPainting(); - if (sw == sh && sh == 0) - m_painter.drawPixmap(QPointF(sx, sy), image->value()); - else - m_painter.drawPixmap(QRect(sx, sy, sw, sh), image->value()); - - scheduleChange(); - } -} - -void Context2D::setSize(int width, int height) -{ - endPainting(); - m_width = width; - m_height = height; - - scheduleChange(); -} - -void Context2D::setSize(const QSize &size) -{ - setSize(size.width(), size.height()); -} - -QSize Context2D::size() const -{ - return m_pixmap.size(); -} - -QPoint Context2D::painterTranslate() const -{ - return m_painterTranslate; -} - -void Context2D::setPainterTranslate(const QPoint &translate) -{ - m_painterTranslate = translate; - m_state.flags |= DirtyTransformationMatrix; -} - -void Context2D::scheduleChange() -{ - QMetaObject::invokeMethod(this, "onScheduleChange", Qt::QueuedConnection, Q_ARG(int, 0)); -} - -void Context2D::onScheduleChange(int interval) -{ - if (m_changeTimerId == -1 && !m_inPaint) - m_changeTimerId = startTimer(interval); -} - -void Context2D::timerEvent(QTimerEvent *e) -{ - if (e->timerId() == m_changeTimerId) { - killTimer(m_changeTimerId); - m_changeTimerId = -1; - endPainting(); - emit changed(); - } else { - QObject::timerEvent(e); - } -} - -QMatrix Context2D::worldMatrix() const -{ - QMatrix mat; - mat.translate(m_painterTranslate.x(), m_painterTranslate.y()); - mat *= m_state.matrix; - return mat; -} - -QT_END_NAMESPACE diff --git a/src/plugins/qmlprofiler/canvas/qdeclarativecontext2d_p.h b/src/plugins/qmlprofiler/canvas/qdeclarativecontext2d_p.h deleted file mode 100644 index cd84e1fa2b..0000000000 --- a/src/plugins/qmlprofiler/canvas/qdeclarativecontext2d_p.h +++ /dev/null @@ -1,326 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#ifndef QDECLARATIVECONTEXT2D_P_H -#define QDECLARATIVECONTEXT2D_P_H - -#include <qpainter.h> -#include <qpainterpath.h> -#include <qpixmap.h> -#include <qstring.h> -#include <qstack.h> -#include <qmetatype.h> -#include <qcoreevent.h> -#include <qvariant.h> - -#include <QJSValue> - -QT_BEGIN_NAMESPACE - -QColor colorFromString(const QString &name); - -class CanvasGradient : public QObject -{ - Q_OBJECT -public: - CanvasGradient(const QGradient &gradient) : m_gradient(gradient) {} - -public slots: - QGradient value() { return m_gradient; } - void addColorStop(float pos, const QString &color) { m_gradient.setColorAt(pos, colorFromString(color));} - -public: - QGradient m_gradient; -}; - -class CanvasImage: public QObject -{ - Q_OBJECT - Q_PROPERTY(QString src READ src WRITE setSrc NOTIFY sourceChanged) - Q_PROPERTY(int width READ width) - Q_PROPERTY(int height READ height) - -public: - CanvasImage() {} - CanvasImage(const QString &url) : m_image(url), m_src(url) {} - CanvasImage(const QPixmap &pixmap) {m_image = pixmap;} - -public slots: - int width() { return m_image.width(); } - int height() { return m_image.height(); } - QPixmap &value() { return m_image; } - QString src() { return m_src; } - void setSrc(const QString &src) { m_src = src; m_image.load(src); emit sourceChanged();} -signals: - void sourceChanged(); - -private: - QPixmap m_image; - QString m_src; -}; - - -class ImageData { -}; - -class Context2D : public QObject -{ - Q_OBJECT - // compositing - Q_PROPERTY(qreal globalAlpha READ globalAlpha WRITE setGlobalAlpha) - Q_PROPERTY(QString globalCompositeOperation READ globalCompositeOperation WRITE setGlobalCompositeOperation) - Q_PROPERTY(QVariant strokeStyle READ strokeStyle WRITE setStrokeStyle) - Q_PROPERTY(QVariant fillStyle READ fillStyle WRITE setFillStyle) - // line caps/joins - Q_PROPERTY(qreal lineWidth READ lineWidth WRITE setLineWidth) - Q_PROPERTY(QString lineCap READ lineCap WRITE setLineCap) - Q_PROPERTY(QString lineJoin READ lineJoin WRITE setLineJoin) - Q_PROPERTY(qreal miterLimit READ miterLimit WRITE setMiterLimit) - // shadows - Q_PROPERTY(qreal shadowOffsetX READ shadowOffsetX WRITE setShadowOffsetX) - Q_PROPERTY(qreal shadowOffsetY READ shadowOffsetY WRITE setShadowOffsetY) - Q_PROPERTY(qreal shadowBlur READ shadowBlur WRITE setShadowBlur) - Q_PROPERTY(QString shadowColor READ shadowColor WRITE setShadowColor) - // fonts - Q_PROPERTY(QString font READ font WRITE setFont) - Q_PROPERTY(QString textBaseline READ textBaseline WRITE setTextBaseline) - Q_PROPERTY(QString textAlign READ textAlign WRITE setTextAlign) - - enum TextBaseLine { Alphabetic=0, Top, Middle, Bottom, Hanging}; - enum TextAlign { Start=0, End, Left, Right, Center}; - -public: - Context2D(QObject *parent = 0); - void setSize(int width, int height); - void setSize(const QSize &size); - QSize size() const; - - QPoint painterTranslate() const; - void setPainterTranslate(const QPoint &); - - void scheduleChange(); - void timerEvent(QTimerEvent *e); - - void clear(); - void reset(); - - QPixmap pixmap() { return m_pixmap; } - - // compositing - qreal globalAlpha() const; // (default 1.0) - QString globalCompositeOperation() const; // (default over) - QVariant strokeStyle() const; // (default black) - QVariant fillStyle() const; // (default black) - - void setGlobalAlpha(qreal alpha); - void setGlobalCompositeOperation(const QString &op); - void setStrokeStyle(const QVariant &style); - void setFillStyle(const QVariant &style); - - // line caps/joins - qreal lineWidth() const; // (default 1) - QString lineCap() const; // "butt", "round", "square" (default "butt") - QString lineJoin() const; // "round", "bevel", "miter" (default "miter") - qreal miterLimit() const; // (default 10) - - void setLineWidth(qreal w); - void setLineCap(const QString &s); - void setLineJoin(const QString &s); - void setMiterLimit(qreal m); - - void setFont(const QString &font); - QString font(); - void setTextBaseline(const QString &font); - QString textBaseline(); - void setTextAlign(const QString &font); - QString textAlign(); - - // shadows - qreal shadowOffsetX() const; // (default 0) - qreal shadowOffsetY() const; // (default 0) - qreal shadowBlur() const; // (default 0) - QString shadowColor() const; // (default black) - - void setShadowOffsetX(qreal x); - void setShadowOffsetY(qreal y); - void setShadowBlur(qreal b); - void setShadowColor(const QString &str); - - struct MouseArea { - QJSValue callback; - QJSValue data; - QRectF rect; - QMatrix matrix; - }; - const QList<MouseArea> &mouseAreas() const; - -public slots: - void save(); // push state on state stack - void restore(); // pop state stack and restore state - - void fillText(const QString &text, qreal x, qreal y); - void strokeText(const QString &text, qreal x, qreal y); - - void setInPaint(bool val){m_inPaint = val;} - void scale(qreal x, qreal y); - void rotate(qreal angle); - void translate(qreal x, qreal y); - void transform(qreal m11, qreal m12, qreal m21, qreal m22, - qreal dx, qreal dy); - void setTransform(qreal m11, qreal m12, qreal m21, qreal m22, - qreal dx, qreal dy); - - CanvasGradient *createLinearGradient(qreal x0, qreal y0, - qreal x1, qreal y1); - CanvasGradient *createRadialGradient(qreal x0, qreal y0, - qreal r0, qreal x1, - qreal y1, qreal r1); - - // rects - void clearRect(qreal x, qreal y, qreal w, qreal h); - void fillRect(qreal x, qreal y, qreal w, qreal h); - void strokeRect(qreal x, qreal y, qreal w, qreal h); - - // mouse - void mouseArea(qreal x, qreal y, qreal w, qreal h, const QJSValue &, const QJSValue & = QJSValue()); - - // path API - void beginPath(); - void closePath(); - void moveTo(qreal x, qreal y); - void lineTo(qreal x, qreal y); - void quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y); - void bezierCurveTo(qreal cp1x, qreal cp1y, - qreal cp2x, qreal cp2y, qreal x, qreal y); - void arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius); - void rect(qreal x, qreal y, qreal w, qreal h); - void arc(qreal x, qreal y, qreal radius, - qreal startAngle, qreal endAngle, - bool anticlockwise); - void fill(); - void stroke(); - void clip(); - bool isPointInPath(qreal x, qreal y) const; - - CanvasImage *createImage(const QString &url); - - // drawing images (no overloads due to QTBUG-11604) - void drawImage(const QVariant &var, qreal dx, qreal dy, qreal dw, qreal dh); - - // pixel manipulation - ImageData getImageData(qreal sx, qreal sy, qreal sw, qreal sh); - void putImageData(ImageData image, qreal dx, qreal dy); - void endPainting(); - -private slots: - void onScheduleChange(int interval); - -signals: - void changed(); - -private: - void setupPainter(); - void beginPainting(); - void updateShadowBuffer(); - - int m_changeTimerId; - QPainterPath m_path; - - enum DirtyFlag { - DirtyTransformationMatrix = 0x00001, - DirtyClippingRegion = 0x00002, - DirtyStrokeStyle = 0x00004, - DirtyFillStyle = 0x00008, - DirtyGlobalAlpha = 0x00010, - DirtyLineWidth = 0x00020, - DirtyLineCap = 0x00040, - DirtyLineJoin = 0x00080, - DirtyMiterLimit = 0x00100, - MDirtyPen = DirtyStrokeStyle - | DirtyLineWidth - | DirtyLineCap - | DirtyLineJoin - | DirtyMiterLimit, - DirtyShadowOffsetX = 0x00200, - DirtyShadowOffsetY = 0x00400, - DirtyShadowBlur = 0x00800, - DirtyShadowColor = 0x01000, - DirtyGlobalCompositeOperation = 0x2000, - DirtyFont = 0x04000, - DirtyTextAlign = 0x08000, - DirtyTextBaseline = 0x10000, - AllIsFullOfDirt = 0xfffff - }; - - struct State { - State() : flags(0) {} - QMatrix matrix; - QPainterPath clipPath; - QBrush strokeStyle; - QBrush fillStyle; - qreal globalAlpha; - qreal lineWidth; - Qt::PenCapStyle lineCap; - Qt::PenJoinStyle lineJoin; - qreal miterLimit; - qreal shadowOffsetX; - qreal shadowOffsetY; - qreal shadowBlur; - QColor shadowColor; - QPainter::CompositionMode globalCompositeOperation; - QFont font; - Context2D::TextAlign textAlign; - Context2D::TextBaseLine textBaseline; - int flags; - }; - - int baseLineOffset(Context2D::TextBaseLine value, const QFontMetrics &metrics); - int textAlignOffset(Context2D::TextAlign value, const QFontMetrics &metrics, const QString &string); - - QMatrix worldMatrix() const; - - QPoint m_painterTranslate; - State m_state; - QStack<State> m_stateStack; - QPixmap m_pixmap; - QList<MouseArea> m_mouseAreas; - QImage m_shadowbuffer; - QVector<QRgb> m_shadowColorIndexBuffer; - QColor m_shadowColorBuffer; - QPainter m_painter; - int m_width, m_height; - bool m_inPaint; -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(CanvasImage*) -Q_DECLARE_METATYPE(CanvasGradient*) - -#endif // QDECLARATIVECONTEXT2D_P_H diff --git a/src/plugins/qmlprofiler/canvas/qmlprofilercanvas.cpp b/src/plugins/qmlprofiler/canvas/qmlprofilercanvas.cpp deleted file mode 100644 index 3503807896..0000000000 --- a/src/plugins/qmlprofiler/canvas/qmlprofilercanvas.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#include "qmlprofilercanvas.h" - -#include "qdeclarativecontext2d_p.h" - -#include <qpixmap.h> -#include <qpainter.h> - -namespace QmlProfiler { -namespace Internal { - -QmlProfilerCanvas::QmlProfilerCanvas() - : m_context2d(new Context2D(this)) -{ - setAcceptedMouseButtons(Qt::LeftButton); - m_drawTimer.setSingleShot(true); - connect(&m_drawTimer, SIGNAL(timeout()), this, SLOT(draw())); - - m_drawTimer.start(); -} - -void QmlProfilerCanvas::requestPaint() -{ - if (m_context2d->size().width() != width() - || m_context2d->size().height() != height()) { - m_drawTimer.start(); - } else { - update(); - } -} - -void QmlProfilerCanvas::requestRedraw() -{ - m_drawTimer.start(); -} - -// called from GUI thread. Draws into m_context2d. -void QmlProfilerCanvas::draw() -{ - QMutexLocker lock(&m_pixmapMutex); - m_context2d->reset(); - m_context2d->setSize(width(), height()); - - if (width() > 0 && height() > 0) - emit drawRegion(m_context2d, QRect(0, 0, width(), height())); - update(); -} - -// called from OpenGL thread. Renders m_context2d into OpenGL buffer. -void QmlProfilerCanvas::paint(QPainter *p) -{ - QMutexLocker lock(&m_pixmapMutex); - p->drawPixmap(0, 0, m_context2d->pixmap()); -} - -void QmlProfilerCanvas::componentComplete() -{ - const QMetaObject *metaObject = this->metaObject(); - int propertyCount = metaObject->propertyCount(); - int requestPaintMethod = metaObject->indexOfMethod("requestPaint()"); - for (int ii = QmlProfilerCanvas::staticMetaObject.propertyCount(); ii < propertyCount; ++ii) { - QMetaProperty p = metaObject->property(ii); - if (p.hasNotifySignal()) - QMetaObject::connect(this, p.notifySignalIndex(), this, requestPaintMethod, 0, 0); - } - QQuickItem::componentComplete(); - requestRedraw(); -} - -void QmlProfilerCanvas::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - QQuickItem::geometryChanged(newGeometry, oldGeometry); - requestRedraw(); -} - -} -} diff --git a/src/plugins/qmlprofiler/canvas/qmlprofilercanvas.h b/src/plugins/qmlprofiler/canvas/qmlprofilercanvas.h deleted file mode 100644 index 4a360d012c..0000000000 --- a/src/plugins/qmlprofiler/canvas/qmlprofilercanvas.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -****************************************************************************/ - -#ifndef QMLPROFILERCANVAS_H -#define QMLPROFILERCANVAS_H - -#include <QQuickPaintedItem> -#include <QTimer> -#include <QMutex> - -QT_BEGIN_NAMESPACE -class Context2D; -QT_END_NAMESPACE - -namespace QmlProfiler { -namespace Internal { - -class QmlProfilerCanvas : public QQuickPaintedItem -{ - Q_OBJECT - -public: - QmlProfilerCanvas(); - -signals: - void drawRegion(Context2D *ctxt, const QRect ®ion); - -public slots: - void requestPaint(); - void requestRedraw(); - -private slots: - void draw(); - -protected: - virtual void paint(QPainter *); - virtual void componentComplete(); - virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - -private: - Context2D *m_context2d; - - QTimer m_drawTimer; - QMutex m_pixmapMutex; -}; - -} -} - -#endif // QMLPROFILERCANVAS_H diff --git a/src/plugins/qmlprofiler/qml/CategoryLabel.qml b/src/plugins/qmlprofiler/qml/CategoryLabel.qml index f8cc12d859..5837918344 100644 --- a/src/plugins/qmlprofiler/qml/CategoryLabel.qml +++ b/src/plugins/qmlprofiler/qml/CategoryLabel.qml @@ -47,7 +47,7 @@ Item { onExpandedChanged: { qmlProfilerModelProxy.setExpanded(modelIndex, categoryIndex, expanded); - backgroundMarks.requestRedraw(); + backgroundMarks.requestPaint(); getDescriptions(); updateHeight(); } diff --git a/src/plugins/qmlprofiler/qml/MainView.qml b/src/plugins/qmlprofiler/qml/MainView.qml index e8bce8ea0d..c7e12a3de7 100644 --- a/src/plugins/qmlprofiler/qml/MainView.qml +++ b/src/plugins/qmlprofiler/qml/MainView.qml @@ -76,19 +76,12 @@ Rectangle { onRangeChanged: { var startTime = zoomControl.startTime(); var endTime = zoomControl.endTime(); - var duration = Math.abs(endTime - startTime); - mainviewTimePerPixel = duration / root.width; + mainviewTimePerPixel = Math.abs(endTime - startTime) / root.width; backgroundMarks.updateMarks(startTime, endTime); view.updateFlickRange(startTime, endTime); - if (duration > 0) { - var candidateWidth = qmlProfilerModelProxy.traceDuration() * - flick.width / duration; - if (flick.contentWidth !== candidateWidth) - flick.contentWidth = candidateWidth; - } - + flick.setContentWidth(); } } @@ -309,8 +302,11 @@ Rectangle { boundsBehavior: Flickable.StopAtBounds // ScrollView will try to deinteractivate it. We don't want that - // as the horizontal flickable is interactive, too. - onInteractiveChanged: interactive = true + // as the horizontal flickable is interactive, too. We do occasionally + // switch to non-interactive ourselves, though. + property bool stayInteractive: true + onInteractiveChanged: interactive = stayInteractive + onStayInteractiveChanged: interactive = stayInteractive // ***** child items TimeMarks { @@ -322,6 +318,12 @@ Rectangle { } Flickable { + function setContentWidth() { + var duration = Math.abs(zoomControl.endTime() - zoomControl.startTime()); + if (duration > 0) + contentWidth = qmlProfilerModelProxy.traceDuration() * width / duration; + } + id: flick anchors.top: parent.top anchors.topMargin: labels.y @@ -333,6 +335,8 @@ Rectangle { boundsBehavior: Flickable.StopAtBounds onContentXChanged: view.updateZoomControl() + onWidthChanged: setContentWidth() + clip:true SelectionRange { @@ -429,6 +433,9 @@ Rectangle { onPressed: { selectionRange.pressedOnCreation(); } + onCanceled: { + selectionRange.releasedOnCreation(); + } onPositionChanged: { selectionRange.movedOnCreation(); } @@ -508,8 +515,6 @@ Rectangle { x: 0 y: 0 - function toggleEnabled() {enabled = !enabled} - function toggleVisible() {visible = !visible} function updateZoomLevel() { zoomSlider.externalUpdate = true; zoomSlider.value = Math.pow((view.endTime - view.startTime) / qmlProfilerModelProxy.traceDuration(), 1 / zoomSlider.exponent) * zoomSlider.maximumValue; diff --git a/src/plugins/qmlprofiler/qml/Overview.qml b/src/plugins/qmlprofiler/qml/Overview.qml index 2168ea79ad..51d1fdb1f6 100644 --- a/src/plugins/qmlprofiler/qml/Overview.qml +++ b/src/plugins/qmlprofiler/qml/Overview.qml @@ -31,9 +31,10 @@ import QtQuick 2.1 import Monitor 1.0 import "Overview.js" as Plotter -Canvas2D { +Canvas { id: canvas objectName: "Overview" + contextType: "2d" // ***** properties height: 50 @@ -45,7 +46,7 @@ Canvas2D { function clearDisplay() { dataReady = false; - requestRedraw(); + requestPaint(); } function updateRange() { @@ -84,18 +85,18 @@ Canvas2D { target: qmlProfilerModelProxy onDataAvailable: { dataReady = true; - requestRedraw(); + requestPaint(); } } // ***** slots - onDrawRegion: { + onPaint: { Plotter.qmlProfilerModelProxy = qmlProfilerModelProxy; if (dataReady) { - Plotter.plot(canvas, ctxt, region); + Plotter.plot(canvas, context, region); } else { - Plotter.drawGraph(canvas, ctxt, region) //just draw the background + Plotter.drawGraph(canvas, context, region) //just draw the background } } diff --git a/src/plugins/qmlprofiler/qml/SelectionRange.qml b/src/plugins/qmlprofiler/qml/SelectionRange.qml index 78e09cfb40..381aa27c74 100644 --- a/src/plugins/qmlprofiler/qml/SelectionRange.qml +++ b/src/plugins/qmlprofiler/qml/SelectionRange.qml @@ -42,6 +42,7 @@ RangeMover { property real duration: Math.max(getWidth() * viewTimePerPixel, 500) property real viewTimePerPixel: 1 property int creationState : 0 + property int creationReference : 0 Connections { target: zoomControl @@ -65,6 +66,7 @@ RangeMover { function reset(setVisible) { setRight(getLeft() + 1); creationState = 0; + creationReference = 0; visible = setVisible; } @@ -75,18 +77,21 @@ RangeMover { pos = width; switch (creationState) { - case 1: { + case 1: + creationReference = pos; setLeft(pos); setRight(pos + 1); break; - } - case 2: { - setLeft(Math.min(getLeft(), pos)); - setRight(Math.max(getRight(), pos)); + case 2: + if (pos > creationReference) { + setLeft(creationReference); + setRight(pos); + } else if (pos < creationReference) { + setLeft(pos); + setRight(creationReference); + } break; } - default: return; - } } @@ -104,6 +109,7 @@ RangeMover { function releasedOnCreation() { if (selectionRange.creationState === 2) { flick.interactive = true; + vertflick.stayInteractive = true; selectionRange.creationState = 3; selectionRangeControl.enabled = false; } @@ -112,6 +118,7 @@ RangeMover { function pressedOnCreation() { if (selectionRange.creationState === 1) { flick.interactive = false; + vertflick.stayInteractive = false; selectionRange.setPos(selectionRangeControl.mouseX + flick.contentX); selectionRange.creationState = 2; } diff --git a/src/plugins/qmlprofiler/qml/TimeDisplay.qml b/src/plugins/qmlprofiler/qml/TimeDisplay.qml index c7340cfa39..97c469f5d3 100644 --- a/src/plugins/qmlprofiler/qml/TimeDisplay.qml +++ b/src/plugins/qmlprofiler/qml/TimeDisplay.qml @@ -30,9 +30,10 @@ import QtQuick 2.1 import Monitor 1.0 -Canvas2D { +Canvas { id: timeDisplay objectName: "TimeDisplay" + contextType: "2d" property real startTime : 0 property real endTime : 0 @@ -43,13 +44,13 @@ Canvas2D { onRangeChanged: { startTime = zoomControl.startTime(); endTime = zoomControl.endTime(); - requestRedraw(); + requestPaint(); } } - onDrawRegion: { - ctxt.fillStyle = "white"; - ctxt.fillRect(0, 0, width, height); + onPaint: { + context.fillStyle = "white"; + context.fillRect(0, 0, width, height); var totalTime = endTime - startTime; var spacing = width / totalTime; @@ -67,50 +68,50 @@ Canvas2D { var initialColor = Math.floor(realStartTime/timePerBlock) % 2; - ctxt.fillStyle = "#000000"; - ctxt.font = "8px sans-serif"; + context.fillStyle = "#000000"; + context.font = "8px sans-serif"; for (var ii = 0; ii < blockCount+1; ii++) { var x = Math.floor(ii*pixelsPerBlock - realStartPos); - ctxt.fillStyle = (ii+initialColor)%2 ? "#E6E6E6":"white"; - ctxt.fillRect(x, 0, pixelsPerBlock, height); + context.fillStyle = (ii+initialColor)%2 ? "#E6E6E6":"white"; + context.fillRect(x, 0, pixelsPerBlock, height); - ctxt.strokeStyle = "#B0B0B0"; - ctxt.beginPath(); - ctxt.moveTo(x, 0); - ctxt.lineTo(x, height); - ctxt.stroke(); + context.strokeStyle = "#B0B0B0"; + context.beginPath(); + context.moveTo(x, 0); + context.lineTo(x, height); + context.stroke(); - ctxt.fillStyle = "#000000"; - ctxt.fillText(prettyPrintTime(ii*timePerBlock + realStartTime), x + 5, height/2 + 5); + context.fillStyle = "#000000"; + context.fillText(prettyPrintTime(ii*timePerBlock + realStartTime), x + 5, height/2 + 5); } - ctxt.strokeStyle = "#525252"; - ctxt.beginPath(); - ctxt.moveTo(0, height-1); - ctxt.lineTo(width, height-1); - ctxt.stroke(); + context.strokeStyle = "#525252"; + context.beginPath(); + context.moveTo(0, height-1); + context.lineTo(width, height-1); + context.stroke(); // gradient borders var gradientDark = "rgba(0, 0, 0, 0.53125)"; var gradientClear = "rgba(0, 0, 0, 0)"; - var grad = ctxt.createLinearGradient(0, 0, 0, 6); + var grad = context.createLinearGradient(0, 0, 0, 6); grad.addColorStop(0,gradientDark); grad.addColorStop(1,gradientClear); - ctxt.fillStyle = grad; - ctxt.fillRect(0, 0, width, 6); + context.fillStyle = grad; + context.fillRect(0, 0, width, 6); - grad = ctxt.createLinearGradient(0, 0, 6, 0); + grad = context.createLinearGradient(0, 0, 6, 0); grad.addColorStop(0,gradientDark); grad.addColorStop(1,gradientClear); - ctxt.fillStyle = grad; - ctxt.fillRect(0, 0, 6, height); + context.fillStyle = grad; + context.fillRect(0, 0, 6, height); - grad = ctxt.createLinearGradient(width, 0, width-6, 0); + grad = context.createLinearGradient(width, 0, width-6, 0); grad.addColorStop(0,gradientDark); grad.addColorStop(1,gradientClear); - ctxt.fillStyle = grad; - ctxt.fillRect(width-6, 0, 6, height); + context.fillStyle = grad; + context.fillRect(width-6, 0, 6, height); } function prettyPrintTime( t ) diff --git a/src/plugins/qmlprofiler/qml/TimeMarks.qml b/src/plugins/qmlprofiler/qml/TimeMarks.qml index 433d35578f..2cef16edf4 100644 --- a/src/plugins/qmlprofiler/qml/TimeMarks.qml +++ b/src/plugins/qmlprofiler/qml/TimeMarks.qml @@ -30,9 +30,10 @@ import QtQuick 2.1 import Monitor 1.0 -Canvas2D { - id: timeDisplay +Canvas { + id: timeMarks objectName: "TimeMarks" + contextType: "2d" property real startTime property real endTime @@ -40,11 +41,13 @@ Canvas2D { Connections { target: labels - onHeightChanged: { requestRedraw(); } + onHeightChanged: requestPaint() } - onDrawRegion: { - drawBackgroundBars( ctxt, region ); + onYChanged: requestPaint() + + onPaint: { + drawBackgroundBars( context, region ); var totalTime = endTime - startTime; var spacing = width / totalTime; @@ -63,23 +66,23 @@ Canvas2D { var lineStart = y < 0 ? -y : 0; var lineEnd = Math.min(height, labels.height - y); - ctxt.fillStyle = "#000000"; - ctxt.font = "8px sans-serif"; + context.fillStyle = "#000000"; + context.font = "8px sans-serif"; for (var ii = 0; ii < blockCount+1; ii++) { var x = Math.floor(ii*pixelsPerBlock - realStartPos); - ctxt.strokeStyle = "#B0B0B0"; - ctxt.beginPath(); - ctxt.moveTo(x, lineStart); - ctxt.lineTo(x, lineEnd); - ctxt.stroke(); + context.strokeStyle = "#B0B0B0"; + context.beginPath(); + context.moveTo(x, lineStart); + context.lineTo(x, lineEnd); + context.stroke(); - ctxt.strokeStyle = "#CCCCCC"; + context.strokeStyle = "#CCCCCC"; for (var jj=1; jj < 5; jj++) { var xx = Math.floor(ii*pixelsPerBlock + jj*pixelsPerSection - realStartPos); - ctxt.beginPath(); - ctxt.moveTo(xx, lineStart); - ctxt.lineTo(xx, lineEnd); - ctxt.stroke(); + context.beginPath(); + context.moveTo(xx, lineStart); + context.lineTo(xx, lineEnd); + context.stroke(); } } } @@ -88,19 +91,19 @@ Canvas2D { if (startTime !== start || endTime !== end) { startTime = start; endTime = end; - requestRedraw(); + requestPaint(); } } - function drawBackgroundBars( ctxt, region ) { + function drawBackgroundBars( context, region ) { var colorIndex = true; // row background var backgroundOffset = y < 0 ? -y : -(y % (2 * root.singleRowHeight)); for (var currentY= backgroundOffset; currentY < Math.min(height, labels.height - y); currentY += root.singleRowHeight) { - ctxt.fillStyle = colorIndex ? "#f0f0f0" : "white"; - ctxt.strokeStyle = colorIndex ? "#f0f0f0" : "white"; - ctxt.fillRect(0, currentY, width, root.singleRowHeight); + context.fillStyle = colorIndex ? "#f0f0f0" : "white"; + context.strokeStyle = colorIndex ? "#f0f0f0" : "white"; + context.fillRect(0, currentY, width, root.singleRowHeight); colorIndex = !colorIndex; } @@ -112,18 +115,18 @@ Canvas2D { if (cumulatedHeight < y) continue; - ctxt.strokeStyle = "#B0B0B0"; - ctxt.beginPath(); - ctxt.moveTo(0, cumulatedHeight - y); - ctxt.lineTo(width, cumulatedHeight - y); - ctxt.stroke(); + context.strokeStyle = "#B0B0B0"; + context.beginPath(); + context.moveTo(0, cumulatedHeight - y); + context.lineTo(width, cumulatedHeight - y); + context.stroke(); } } // bottom if (height > labels.height - y) { - ctxt.fillStyle = "#f5f5f5"; - ctxt.fillRect(0, labels.height - y, width, Math.min(height - labels.height + y, labelsTail.height)); + context.fillStyle = "#f5f5f5"; + context.fillRect(0, labels.height - y, width, Math.min(height - labels.height + y, labelsTail.height)); } } } diff --git a/src/plugins/qmlprofiler/qmlprofiler.pro b/src/plugins/qmlprofiler/qmlprofiler.pro index 8be8423533..aa23d616c8 100644 --- a/src/plugins/qmlprofiler/qmlprofiler.pro +++ b/src/plugins/qmlprofiler/qmlprofiler.pro @@ -3,7 +3,6 @@ DEFINES += QMLPROFILER_LIBRARY QT += network qml quick include(../../qtcreatorplugin.pri) -include(canvas/canvas.pri) SOURCES += \ qmlprofilerplugin.cpp \ @@ -31,7 +30,8 @@ SOURCES += \ qmlprofilertracefile.cpp \ abstracttimelinemodel.cpp \ timelinemodelaggregator.cpp \ - qmlprofilerpainteventsmodelproxy.cpp + qmlprofilerpainteventsmodelproxy.cpp \ + sortedtimelinemodel.cpp HEADERS += \ qmlprofilerconstants.h \ @@ -62,7 +62,8 @@ HEADERS += \ qmlprofilertracefile.h \ abstracttimelinemodel.h \ timelinemodelaggregator.h \ - qmlprofilerpainteventsmodelproxy.h + qmlprofilerpainteventsmodelproxy.h \ + sortedtimelinemodel.h RESOURCES += \ qml/qmlprofiler.qrc diff --git a/src/plugins/qmlprofiler/qmlprofiler.qbs b/src/plugins/qmlprofiler/qmlprofiler.qbs index 507ce1093e..018019c49a 100644 --- a/src/plugins/qmlprofiler/qmlprofiler.qbs +++ b/src/plugins/qmlprofiler/qmlprofiler.qbs @@ -50,23 +50,13 @@ QtcPlugin { "qmlprofilerviewmanager.cpp", "qmlprofilerviewmanager.h", "qv8profilerdatamodel.cpp", "qv8profilerdatamodel.h", "qv8profilereventview.h", "qv8profilereventview.cpp", + "sortedtimelinemodel.h", "sortedtimelinemodel.cpp", "timelinemodelaggregator.cpp", "timelinemodelaggregator.h", "timelinerenderer.cpp", "timelinerenderer.h", ] } Group { - name: "Canvas" - prefix: "canvas/" - files: [ - "qdeclarativecanvas.cpp", "qdeclarativecanvas_p.h", - "qdeclarativecanvastimer.cpp", "qdeclarativecanvastimer_p.h", - "qdeclarativecontext2d.cpp", "qdeclarativecontext2d_p.h", - "qmlprofilercanvas.cpp", "qmlprofilercanvas.h" - ] - } - - Group { name: "QML" prefix: "qml/" files: [ diff --git a/src/plugins/qmlprofiler/qmlprofilerplugin.cpp b/src/plugins/qmlprofiler/qmlprofilerplugin.cpp index e4fd95a5a4..342035c19a 100644 --- a/src/plugins/qmlprofiler/qmlprofilerplugin.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerplugin.cpp @@ -46,7 +46,7 @@ namespace Internal { class QmlProfilerAction : public AnalyzerAction { public: - QmlProfilerAction() {} + explicit QmlProfilerAction(QObject *parent = 0) : AnalyzerAction(parent) { } }; bool QmlProfilerPlugin::debugOutput = false; @@ -65,7 +65,7 @@ bool QmlProfilerPlugin::initialize(const QStringList &arguments, QString *errorS "The QML Profiler can be used to find performance bottlenecks in " "applications using QML."); - action = new QmlProfilerAction; + action = new QmlProfilerAction(this); action->setId("QmlProfiler.Local"); action->setTool(tool); action->setText(tr("QML Profiler")); @@ -74,7 +74,7 @@ bool QmlProfilerPlugin::initialize(const QStringList &arguments, QString *errorS action->setMenuGroup(Constants::G_ANALYZER_TOOLS); AnalyzerManager::addAction(action); - action = new QmlProfilerAction; + action = new QmlProfilerAction(this); action->setId("QmlProfiler.Remote"); action->setTool(tool); action->setText(tr("QML Profiler (External)")); diff --git a/src/plugins/qmlprofiler/qmlprofilerplugin.h b/src/plugins/qmlprofiler/qmlprofilerplugin.h index 0550fa1eec..aafdea86b9 100644 --- a/src/plugins/qmlprofiler/qmlprofilerplugin.h +++ b/src/plugins/qmlprofiler/qmlprofilerplugin.h @@ -58,8 +58,6 @@ public: private: QList<AbstractTimelineModel*> timelineModels; - - }; } // namespace Internal diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 5fbb3307b5..2f4afa09d7 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -41,9 +41,6 @@ #include <analyzerbase/analyzermanager.h> #include <analyzerbase/analyzerruncontrol.h> -#include "canvas/qdeclarativecontext2d_p.h" -#include "canvas/qmlprofilercanvas.h" - #include <utils/fancymainwindow.h> #include <utils/fileinprojectfinder.h> #include <utils/qtcassert.h> @@ -119,9 +116,6 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) d->m_profilerState = 0; d->m_viewContainer = 0; - qmlRegisterType<QmlProfilerCanvas>("Monitor", 1, 0, "Canvas2D"); - qmlRegisterType<Context2D>(); - qmlRegisterType<CanvasGradient>(); qmlRegisterType<TimelineRenderer>("Monitor", 1, 0,"TimelineRenderer"); d->m_profilerState = new QmlProfilerStateManager(this); diff --git a/src/plugins/qmlprofiler/qmlprofilertraceview.cpp b/src/plugins/qmlprofiler/qmlprofilertraceview.cpp index 645c17b60b..395be21696 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceview.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceview.cpp @@ -192,10 +192,22 @@ void QmlProfilerTraceView::reset() connect(this, SIGNAL(jumpToNext()), rootObject, SLOT(nextEvent())); connect(rootObject, SIGNAL(selectedEventChanged(int)), this, SIGNAL(selectedEventChanged(int))); connect(rootObject, SIGNAL(changeToolTip(QString)), this, SLOT(updateToolTip(QString))); + connect(this, SIGNAL(enableToolbar(bool)), this, SLOT(setZoomSliderEnabled(bool))); + connect(this, SIGNAL(showZoomSlider(bool)), this, SLOT(setZoomSliderVisible(bool))); +} - QObject *zoomSlider = rootObject->findChild<QObject*>(QLatin1String("zoomSliderToolBar")); - connect(this, SIGNAL(enableToolbar(bool)), zoomSlider, SLOT(toggleEnabled())); - connect(this, SIGNAL(showZoomSlider(bool)), zoomSlider, SLOT(toggleVisible())); +void QmlProfilerTraceView::setZoomSliderEnabled(bool enabled) +{ + QQuickItem *zoomSlider = d->m_mainView->rootObject()->findChild<QQuickItem*>(QLatin1String("zoomSliderToolBar")); + if (zoomSlider->isEnabled() != enabled) + zoomSlider->setEnabled(enabled); +} + +void QmlProfilerTraceView::setZoomSliderVisible(bool visible) +{ + QQuickItem *zoomSlider = d->m_mainView->rootObject()->findChild<QQuickItem*>(QLatin1String("zoomSliderToolBar")); + if (zoomSlider->isVisible() != visible) + zoomSlider->setVisible(visible); } QWidget *QmlProfilerTraceView::createToolbar() diff --git a/src/plugins/qmlprofiler/qmlprofilertraceview.h b/src/plugins/qmlprofiler/qmlprofilertraceview.h index da8f66966a..d027a4dabf 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceview.h +++ b/src/plugins/qmlprofiler/qmlprofilertraceview.h @@ -102,6 +102,8 @@ private slots: void profilerStateChanged(); void clientRecordingChanged(); void serverRecordingChanged(); + void setZoomSliderEnabled(bool enabled); + void setZoomSliderVisible(bool visible); signals: void gotoSourceLocation(const QString &fileUrl, int lineNumber, int columNumber); diff --git a/src/plugins/qmlprofiler/sortedtimelinemodel.cpp b/src/plugins/qmlprofiler/sortedtimelinemodel.cpp new file mode 100644 index 0000000000..567c44981f --- /dev/null +++ b/src/plugins/qmlprofiler/sortedtimelinemodel.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +/*! + \class QmlProfiler::SortedTimelineModel + \brief Sorted model for timeline data + + The SortedTimelineModel lets you keep any kind of range data sorted by + both start and end times, so that visible ranges can easily be computed. +*/ + +/*! + \fn SortedTimelineModel::clear() + Clears the ranges and their end times. +*/ + +/*! + \fn int SortedTimelineModel::count() const + Returns the number of ranges in the model. +*/ + +/*! + \fn qint64 SortedTimelineModel::firstStartTime() const + Returns the begin of the first range in the model. +*/ + +/*! + \fn qint64 SortedTimelineModel::lastEndTime() const + Returns the end of the last range in the model. +*/ + +/*! + \fn const SortedTimelineModel<Data>::Range &SortedTimelineModel::range(int index) const + Returns the range data at the specified index. +*/ + +/*! + \fn Data &SortedTimelineModel::data(int index) + Returns modifiable user data for the range at the specified index. +*/ + +/*! + \fn int SortedTimelineModel::insert(qint64 startTime, qint64 duration, const Data &item) + Inserts the given data at the given time position and returns its index. +*/ + +/*! + \fn int SortedTimelineModel::insertStart(qint64 startTime, const Data &item) + Inserts the given data as range start at the given time position and + returns its index. The range end isn't set. +*/ + +/*! + \fn int SortedTimelineModel::insertEnd(int index, qint64 duration) + Adds a range end for the given start index. +*/ + +/*! + \fn int SortedTimelineModel::findFirstIndexNoParents(qint64 startTime) const + Looks up the first range with an end time greater than the given time and + returns its index. If no such range is found it returns -1. +*/ + +/*! + \fn int SortedTimelineModel::findFirstIndex(qint64 startTime) const + Looks up the first range with an end time greater than the given time and + returns its parent's index. If no such range is found it returns -1. If there + is no parent it returns the found range's index. The parent of a range is the + range with the lowest start time that completely covers the child range. + "Completely covers" means: + parent.startTime <= child.startTime && parent.endTime >= child.endTime +*/ + +/*! + \fn int SortedTimelineModel::findLastIndex(qint64 endTime) const + Looks up the last range with a start time smaller than the given time and + returns its index. If no such range is found it returns -1. +*/ + +/*! + \fn void computeNesting() + Compute all ranges' parents. + \sa findFirstIndex +*/ diff --git a/src/plugins/qmlprofiler/sortedtimelinemodel.h b/src/plugins/qmlprofiler/sortedtimelinemodel.h new file mode 100644 index 0000000000..80f78f2fe2 --- /dev/null +++ b/src/plugins/qmlprofiler/sortedtimelinemodel.h @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef SORTEDTIMELINEMODEL_H +#define SORTEDTIMELINEMODEL_H + +#include <QVector> +#include <QLinkedList> + +namespace QmlProfiler { + +template<class Data> +class SortedTimelineModel { +public: + struct Range : public Data { + Range() : Data(), start(-1), duration(-1), parent(-1) {} + Range(qint64 start, qint64 duration, const Data &item) : + Data(item), start(start), duration(duration), parent(-1) {} + qint64 start; + qint64 duration; + int parent; + inline qint64 timestamp() const {return start;} + }; + + struct RangeEnd { + RangeEnd() : startIndex(-1), end(-1) {} + RangeEnd(int startIndex, qint64 end) : + startIndex(startIndex), end(end) {} + int startIndex; + qint64 end; + inline qint64 timestamp() const {return end;} + }; + + void clear() + { + ranges.clear(); + endTimes.clear(); + } + + inline int count() const { return ranges.count(); } + + inline qint64 lastEndTime() const { return endTimes.last().end; } + inline qint64 firstStartTime() const { return ranges.first().start; } + + inline const Range &range(int index) { return ranges[index]; } + inline Data &data(int index) { return ranges[index]; } + + inline int insert(qint64 startTime, qint64 duration, const Data &item) + { + /* Doing insert-sort here is preferable as most of the time the times will actually be + * presorted in the right way. So usually this will just result in appending. */ + int index = insertSorted(ranges, Range(startTime, duration, item)); + insertSorted(endTimes, RangeEnd(index, startTime + duration)); + return index; + } + + inline int insertStart(qint64 startTime, const Data &item) + { + return insertSorted(ranges, Range(startTime, 0, item)); + } + + inline void insertEnd(int index, qint64 duration) + { + ranges[index].duration = duration; + insertSorted(endTimes, RangeEnd(index, ranges[index].start + duration)); + } + + inline int findFirstIndex(qint64 startTime) const + { + int index = findFirstIndexNoParents(startTime); + if (index == -1) + return -1; + int parent = ranges[index].parent; + return parent == -1 ? index : parent; + } + + inline int findFirstIndexNoParents(qint64 startTime) const + { + // in the "endtime" list, find the first event that ends after startTime + if (endTimes.isEmpty()) + return -1; + if (endTimes.count() == 1 || endTimes.first().end >= startTime) + return endTimes.first().startIndex; + if (endTimes.last().end <= startTime) + return -1; + + return endTimes[lowerBound(endTimes, startTime) + 1].startIndex; + } + + inline int findLastIndex(qint64 endTime) const + { + // in the "starttime" list, find the last event that starts before endtime + if (ranges.isEmpty() || ranges.first().start >= endTime) + return -1; + if (ranges.count() == 1) + return 0; + if (ranges.last().start <= endTime) + return ranges.count() - 1; + + return lowerBound(ranges, endTime); + } + + inline void computeNesting() + { + QLinkedList<int> parents; + for (int range = 0; range != count(); ++range) { + Range ¤t = ranges[range]; + for (QLinkedList<int>::iterator parent = parents.begin(); parent != parents.end();) { + qint64 parentEnd = ranges[*parent].start + ranges[*parent].duration; + if (parentEnd < current.start) { + parent = parents.erase(parent); + } else if (parentEnd >= current.start + current.duration) { + current.parent = *parent; + break; + } else { + ++parent; + } + } + parents.append(range); + } + } + +protected: + template<typename RangeDelimiter> + static inline int insertSorted(QVector<RangeDelimiter> &container, const RangeDelimiter &item) + { + for (int i = container.count();;) { + if (i == 0) { + container.prepend(item); + return 0; + } + if (container[--i].timestamp() <= item.timestamp()) { + container.insert(++i, item); + return i; + } + } + } + + template<typename RangeDelimiter> + static inline int lowerBound(const QVector<RangeDelimiter> container, qint64 time) + { + int fromIndex = 0; + int toIndex = container.count() - 1; + while (toIndex - fromIndex > 1) { + int midIndex = (fromIndex + toIndex)/2; + if (container[midIndex].timestamp() < time) + fromIndex = midIndex; + else + toIndex = midIndex; + } + + return fromIndex; + } + + QVector<Range> ranges; + QVector<RangeEnd> endTimes; +}; + +} + +#endif diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp index 32bc461c14..eac59378a0 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp @@ -118,7 +118,7 @@ QmlProjectItem *QmlProjectFileFormat::parseProjectFile(const QString &fileName, setupFileFilterItem(cssFileFilterItem, childNode); projectItem->appendContent(cssFileFilterItem); } else { - qWarning() << "Unkwown type:" << childNode->name(); + qWarning() << "Unknown type:" << childNode->name(); } } return projectItem; diff --git a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp index bbf8165091..d35faf01b9 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp @@ -176,7 +176,11 @@ QList<ProjectExplorer::ProjectNode::ProjectAction> QmlProjectNode::supportedActi QList<ProjectAction> actions; actions.append(AddNewFile); actions.append(EraseFile); - actions.append(Rename); + if (node->nodeType() == ProjectExplorer::FileNodeType) { + ProjectExplorer::FileNode *fileNode = static_cast<ProjectExplorer::FileNode *>(node); + if (fileNode->fileType() != ProjectExplorer::ProjectFileType) + actions.append(Rename); + } return actions; } diff --git a/src/plugins/qnx/blackberrycertificate.cpp b/src/plugins/qnx/blackberrycertificate.cpp index b964bd5b14..088a51f408 100644 --- a/src/plugins/qnx/blackberrycertificate.cpp +++ b/src/plugins/qnx/blackberrycertificate.cpp @@ -34,6 +34,7 @@ #include "blackberryconfigurationmanager.h" #include "blackberryndkprocess.h" +#include <utils/environment.h> #include <utils/hostosinfo.h> #include <QProcess> @@ -52,6 +53,8 @@ BlackBerryCertificate::BlackBerryCertificate(const QString &fileName, m_process(new QProcess(this)) { m_process->setProcessChannelMode(QProcess::MergedChannels); + m_process->setEnvironment(Utils::EnvironmentItem::toStringList( + BlackBerryConfigurationManager::instance().defaultQnxEnv())); } void BlackBerryCertificate::load() diff --git a/src/plugins/qnx/blackberryconfiguration.cpp b/src/plugins/qnx/blackberryconfiguration.cpp index 9125b07a62..ec6f95587d 100644 --- a/src/plugins/qnx/blackberryconfiguration.cpp +++ b/src/plugins/qnx/blackberryconfiguration.cpp @@ -33,7 +33,8 @@ #include "blackberryqtversion.h" #include "qnxtoolchain.h" -#include "qnxutils.h" + +#include <utils/qtcassert.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/kitmanager.h> @@ -62,14 +63,30 @@ using namespace Debugger; namespace Qnx { namespace Internal { -BlackBerryConfiguration::BlackBerryConfiguration(const FileName &ndkEnvFile, bool isAutoDetected, - const QString &displayName) +BlackBerryConfiguration::BlackBerryConfiguration(const NdkInstallInformation &ndkInstallInfo) + : m_isAutoDetected(true) +{ + QString envFilePath = QnxUtils::envFilePath(ndkInstallInfo.path, ndkInstallInfo.version); + QTC_ASSERT(!envFilePath.isEmpty(), return); + m_ndkEnvFile = Utils::FileName::fromString(envFilePath); + m_displayName = ndkInstallInfo.name; + m_qnxEnv = QnxUtils::qnxEnvironmentFromNdkFile(m_ndkEnvFile.toString()); + QString sep = QString::fromLatin1("/qnx6"); + // The QNX_TARGET value is using Unix-like separator on all platforms. + m_targetName = ndkInstallInfo.target.split(sep).first().split(QLatin1Char('/')).last(); + m_qnxHost = ndkInstallInfo.host; + m_sysRoot = FileName::fromString(ndkInstallInfo.target); + m_version = BlackBerryVersionNumber(ndkInstallInfo.version); + ctor(); +} + +BlackBerryConfiguration::BlackBerryConfiguration(const FileName &ndkEnvFile) + : m_isAutoDetected(false) { - Q_ASSERT(!QFileInfo(ndkEnvFile.toString()).isDir()); + QTC_ASSERT(!QFileInfo(ndkEnvFile.toString()).isDir(), return); m_ndkEnvFile = ndkEnvFile; - m_isAutoDetected = isAutoDetected; - QString ndkPath = ndkEnvFile.parentDir().toString(); - m_displayName = displayName.isEmpty() ? ndkPath.split(QDir::separator()).last() : displayName; + QString ndkPath = m_ndkEnvFile.parentDir().toString(); + m_displayName = ndkPath.split(QDir::separator()).last(); m_qnxEnv = QnxUtils::qnxEnvironmentFromNdkFile(m_ndkEnvFile.toString()); QString ndkTarget; @@ -89,6 +106,15 @@ BlackBerryConfiguration::BlackBerryConfiguration(const FileName &ndkEnvFile, boo if (QDir(ndkTarget).exists()) m_sysRoot = FileName::fromString(ndkTarget); + m_version = BlackBerryVersionNumber::fromNdkEnvFileName(QFileInfo(m_ndkEnvFile.toString()).baseName()); + if (m_version.isEmpty()) + m_version = BlackBerryVersionNumber::fromTargetName(m_targetName); + + ctor(); +} + +void BlackBerryConfiguration::ctor() +{ FileName qmake4Path = QnxUtils::executableWithExtension(FileName::fromString(m_qnxHost + QLatin1String("/usr/bin/qmake"))); FileName qmake5Path = QnxUtils::executableWithExtension(FileName::fromString(m_qnxHost + QLatin1String("/usr/bin/qt5/qmake"))); FileName gccPath = QnxUtils::executableWithExtension(FileName::fromString(m_qnxHost + QLatin1String("/usr/bin/qcc"))); @@ -131,6 +157,11 @@ QString BlackBerryConfiguration::qnxHost() const return m_qnxHost; } +BlackBerryVersionNumber BlackBerryConfiguration::version() const +{ + return m_version; +} + bool BlackBerryConfiguration::isAutoDetected() const { return m_isAutoDetected; diff --git a/src/plugins/qnx/blackberryconfiguration.h b/src/plugins/qnx/blackberryconfiguration.h index 1b31d186b3..9701e43485 100644 --- a/src/plugins/qnx/blackberryconfiguration.h +++ b/src/plugins/qnx/blackberryconfiguration.h @@ -32,6 +32,8 @@ #ifndef BLACKBERRYCONFIGURATIONS_H #define BLACKBERRYCONFIGURATIONS_H +#include "qnxutils.h" +#include "blackberryversionnumber.h" #include "qnxconstants.h" #include <utils/environment.h> @@ -60,13 +62,15 @@ class BlackBerryConfiguration { Q_DECLARE_TR_FUNCTIONS(Qnx::Internal::BlackBerryConfiguration) public: - BlackBerryConfiguration(const Utils::FileName &ndkEnvFile, bool isAutoDetected, const QString &displayName = QString()); + BlackBerryConfiguration(const NdkInstallInformation &ndkInstallInfo); + BlackBerryConfiguration(const Utils::FileName &ndkEnvFile); bool activate(); void deactivate(); QString ndkPath() const; QString displayName() const; QString targetName() const; QString qnxHost() const; + BlackBerryVersionNumber version() const; bool isAutoDetected() const; bool isActive() const; bool isValid() const; @@ -84,6 +88,7 @@ private: QString m_targetName; QString m_qnxHost; bool m_isAutoDetected; + BlackBerryVersionNumber m_version; Utils::FileName m_ndkEnvFile; Utils::FileName m_qmake4BinaryFile; Utils::FileName m_qmake5BinaryFile; @@ -93,6 +98,7 @@ private: Utils::FileName m_sysRoot; QList<Utils::EnvironmentItem> m_qnxEnv; + void ctor(); QnxAbstractQtVersion* createQtVersion( const Utils::FileName &qmakePath, Qnx::QnxArchitecture arch, const QString &versionName); QnxToolChain* createToolChain( diff --git a/src/plugins/qnx/blackberryconfigurationmanager.cpp b/src/plugins/qnx/blackberryconfigurationmanager.cpp index 7af64cc3d0..548f5fb5ae 100644 --- a/src/plugins/qnx/blackberryconfigurationmanager.cpp +++ b/src/plugins/qnx/blackberryconfigurationmanager.cpp @@ -66,6 +66,11 @@ const QLatin1String ManualNDKsGroup("ManualNDKs"); const QLatin1String ActiveNDKsGroup("ActiveNDKs"); } +static bool sortConfigurationsByVersion(const BlackBerryConfiguration *a, const BlackBerryConfiguration *b) +{ + return a->version() > b->version(); +} + BlackBerryConfigurationManager::BlackBerryConfigurationManager(QObject *parent) :QObject(parent) { @@ -90,8 +95,7 @@ void BlackBerryConfigurationManager::loadManualConfigurations() ndkEnvPath = QnxUtils::envFilePath(ndkPath); } - BlackBerryConfiguration *config = new BlackBerryConfiguration(Utils::FileName::fromString(ndkEnvPath), - false); + BlackBerryConfiguration *config = new BlackBerryConfiguration(Utils::FileName::fromString(ndkEnvPath)); if (!addConfiguration(config)) delete config; @@ -106,9 +110,7 @@ void BlackBerryConfigurationManager::loadAutoDetectedConfigurations() { QStringList activePaths = activeConfigurationNdkEnvPaths(); foreach (const NdkInstallInformation &ndkInfo, QnxUtils::installedNdks()) { - QString envFilePath = QnxUtils::envFilePath(ndkInfo.path, ndkInfo.version); - BlackBerryConfiguration *config = new BlackBerryConfiguration(Utils::FileName::fromString(envFilePath), - true, ndkInfo.name); + BlackBerryConfiguration *config = new BlackBerryConfiguration(ndkInfo); if (!addConfiguration(config)) { delete config; continue; @@ -242,7 +244,9 @@ bool BlackBerryConfigurationManager::addConfiguration(BlackBerryConfiguration *c } if (config->isValid()) { - m_configs.append(config); + QList<BlackBerryConfiguration *>::iterator it = qLowerBound(m_configs.begin(), m_configs.end(), + config, &sortConfigurationsByVersion); + m_configs.insert(it, config); return true; } diff --git a/src/plugins/qnx/blackberrydebugtokenrequestdialog.cpp b/src/plugins/qnx/blackberrydebugtokenrequestdialog.cpp index 37d8a199e2..8585cec354 100644 --- a/src/plugins/qnx/blackberrydebugtokenrequestdialog.cpp +++ b/src/plugins/qnx/blackberrydebugtokenrequestdialog.cpp @@ -143,9 +143,24 @@ void BlackBerryDebugTokenRequestDialog::requestDebugToken() BlackBerryConfigurationManager &configuration = BlackBerryConfigurationManager::instance(); + bool ok; + const QString cskPassword = m_utils.cskPassword(this, &ok); + + if (!ok) { + setBusy(false); + return; + } + + const QString certificatePassword = m_utils.certificatePassword(this, &ok); + + if (!ok) { + setBusy(false); + return; + } + m_requester->requestDebugToken(m_ui->debugTokenPath->path(), - m_utils.cskPassword(), configuration.defaultKeystorePath(), - m_utils.certificatePassword(), m_ui->devicePin->text()); + cskPassword, configuration.defaultKeystorePath(), + certificatePassword, m_ui->devicePin->text()); } void BlackBerryDebugTokenRequestDialog::setDefaultPath() @@ -235,6 +250,11 @@ void BlackBerryDebugTokenRequestDialog::debugTokenArrived(int status) break; } + QFile file(m_ui->debugTokenPath->path()); + + if (file.exists()) + file.remove(); + QMessageBox::critical(this, tr("Error"), errorString); setBusy(false); diff --git a/src/plugins/qnx/blackberrydevicelistdetector.cpp b/src/plugins/qnx/blackberrydevicelistdetector.cpp index 5598a4150c..e3892de75b 100644 --- a/src/plugins/qnx/blackberrydevicelistdetector.cpp +++ b/src/plugins/qnx/blackberrydevicelistdetector.cpp @@ -30,8 +30,11 @@ #include "blackberrydevicelistdetector.h" +#include "blackberryconfigurationmanager.h" #include "blackberryndkprocess.h" +#include <utils/environment.h> + #include <QStringList> namespace Qnx { @@ -53,6 +56,8 @@ void BlackBerryDeviceListDetector::detectDeviceList() if (m_process->state() != QProcess::NotRunning) return; + m_process->setEnvironment(Utils::EnvironmentItem::toStringList( + BlackBerryConfigurationManager::instance().defaultQnxEnv())); const QString command = BlackBerryNdkProcess::resolveNdkToolPath(QLatin1String("blackberry-deploy")); QStringList arguments; arguments << QLatin1String("-devices"); diff --git a/src/plugins/qnx/blackberryinstallwizardpages.cpp b/src/plugins/qnx/blackberryinstallwizardpages.cpp index b2bd3f5dc0..5ab46033b1 100644 --- a/src/plugins/qnx/blackberryinstallwizardpages.cpp +++ b/src/plugins/qnx/blackberryinstallwizardpages.cpp @@ -479,7 +479,7 @@ void BlackBerryInstallWizardFinalPage::initializePage() BlackBerryConfiguration *config = configManager.configurationFromEnvFile(Utils::FileName::fromString(m_data.ndkPath)); if (!config) { - config = new BlackBerryConfiguration(Utils::FileName::fromString(m_data.ndkPath), false); + config = new BlackBerryConfiguration(Utils::FileName::fromString(m_data.ndkPath)); if (!configManager.addConfiguration(config)) { delete config; // TODO: more explicit error message! diff --git a/src/plugins/qnx/blackberrykeyswidget.cpp b/src/plugins/qnx/blackberrykeyswidget.cpp index 8a3715279d..4698d95895 100644 --- a/src/plugins/qnx/blackberrykeyswidget.cpp +++ b/src/plugins/qnx/blackberrykeyswidget.cpp @@ -68,6 +68,8 @@ void BlackBerryKeysWidget::certificateLoaded(int status) switch (status) { case BlackBerryCertificate::Success: m_ui->certificateAuthor->setText(m_utils.defaultCertificate()->author()); + m_ui->certificateAuthor->setVisible(true); + m_ui->authorLabel->setVisible(true); m_ui->openCertificateButton->setVisible(false); break; case BlackBerryCertificate::WrongPassword: @@ -130,9 +132,18 @@ void BlackBerryKeysWidget::updateCertificateSection() BlackBerryConfigurationManager &configManager = BlackBerryConfigurationManager::instance(); m_ui->certificatePath->setText(configManager.defaultKeystorePath()); - m_ui->certificateAuthor->setText(tr("Loading...")); - loadDefaultCertificate(); + const BlackBerryCertificate *certificate = m_utils.defaultCertificate(); + + if (certificate) { + m_ui->certificateAuthor->setText(certificate->author()); + m_ui->openCertificateButton->setVisible(false); + return; + } + + m_ui->openCertificateButton->setVisible(true); + m_ui->certificateAuthor->setVisible(false); + m_ui->authorLabel->setVisible(false); } else { setCreateCertificateVisible(true); } @@ -157,16 +168,8 @@ void BlackBerryKeysWidget::updateKeysSection() void BlackBerryKeysWidget::loadDefaultCertificate() { - const BlackBerryCertificate *certificate = m_utils.defaultCertificate(); - - if (certificate) { - m_ui->certificateAuthor->setText(certificate->author()); - m_ui->openCertificateButton->setVisible(false); - return; - } - connect(&m_utils, SIGNAL(defaultCertificateLoaded(int)), this, SLOT(certificateLoaded(int))); - m_utils.openDefaultCertificate(); + m_utils.openDefaultCertificate(this); } void BlackBerryKeysWidget::setCertificateError(const QString &error) diff --git a/src/plugins/qnx/blackberryndkprocess.cpp b/src/plugins/qnx/blackberryndkprocess.cpp index d3d9bb3291..1c3cc9f3c7 100644 --- a/src/plugins/qnx/blackberryndkprocess.cpp +++ b/src/plugins/qnx/blackberryndkprocess.cpp @@ -46,6 +46,8 @@ BlackBerryNdkProcess::BlackBerryNdkProcess(const QString &command, QObject *pare m_command(command) { m_process->setProcessChannelMode(QProcess::MergedChannels); + m_process->setEnvironment(Utils::EnvironmentItem::toStringList( + BlackBerryConfigurationManager::instance().defaultQnxEnv())); connect(m_process, SIGNAL(started()), this, SIGNAL(started())); connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), diff --git a/src/plugins/qnx/blackberryndksettingswidget.cpp b/src/plugins/qnx/blackberryndksettingswidget.cpp index a1982539e7..c620e334e6 100644 --- a/src/plugins/qnx/blackberryndksettingswidget.cpp +++ b/src/plugins/qnx/blackberryndksettingswidget.cpp @@ -124,6 +124,7 @@ void BlackBerryNDKSettingsWidget::launchBlackBerrySetupWizard() const } BlackBerrySetupWizard wizard; + connect(&wizard, SIGNAL(ndkTargetsUpdated()), this, SLOT(updateNdkList())); wizard.exec(); } @@ -148,16 +149,7 @@ void BlackBerryNDKSettingsWidget::updateInfoTable(QTreeWidgetItem* currentItem) m_ui->ndkPathLabel->setText(QDir::toNativeSeparators(config->ndkPath())); m_ui->hostLabel->setText(QDir::toNativeSeparators(config->qnxHost())); m_ui->targetLabel->setText(QDir::toNativeSeparators(config->sysRoot().toString())); - m_ui->versionLabel->clear(); - // TODO: Add a versionNumber attribute for the BlackBerryConfiguration class - if (config->isAutoDetected()) { - foreach (const NdkInstallInformation &ndkInfo, QnxUtils::installedNdks()) { - if (ndkInfo.name == config->displayName()) { - m_ui->versionLabel->setText(ndkInfo.version); - break; - } - } - } + m_ui->versionLabel->setText(config->version().toString()); updateUi(currentItem, config); } diff --git a/src/plugins/qnx/blackberrysetupwizard.cpp b/src/plugins/qnx/blackberrysetupwizard.cpp index e5214b0a0f..6cdbd3e64e 100644 --- a/src/plugins/qnx/blackberrysetupwizard.cpp +++ b/src/plugins/qnx/blackberrysetupwizard.cpp @@ -93,6 +93,8 @@ BlackBerrySetupWizard::BlackBerrySetupWizard(QWidget *parent) : m_uploader = new BlackBerryDebugTokenUploader(this); m_keyGenerator = new QSsh::SshKeyGenerator; + connect(m_ndkPage, SIGNAL(targetsUpdated()), + this, SIGNAL(ndkTargetsUpdated())); connect(m_deviceInfo, SIGNAL(finished(int)), this, SLOT(deviceInfoFinished(int))); connect(m_requester, SIGNAL(finished(int)), @@ -215,6 +217,13 @@ void BlackBerrySetupWizard::debugTokenArrived(int status) break; } + BlackBerryConfigurationManager &configuration = BlackBerryConfigurationManager::instance(); + + QFile dt(configuration.defaultKeystorePath()); + + if (dt.exists()) + dt.remove(); + QMessageBox::critical(this, tr("Error"), errorString); reset(); @@ -405,8 +414,13 @@ void BlackBerrySetupWizard::requestDebugToken() BlackBerryConfigurationManager &configuration = BlackBerryConfigurationManager::instance(); + bool ok; + const QString cskPassword = m_utils.cskPassword(this, &ok); + if (!ok) + return; + m_requester->requestDebugToken(configuration.defaultDebugTokenPath(), - m_utils.cskPassword(), configuration.defaultKeystorePath(), certificatePassword(), m_devicePin); + cskPassword, configuration.defaultKeystorePath(), certificatePassword(), m_devicePin); } void BlackBerrySetupWizard::uploadDebugToken() diff --git a/src/plugins/qnx/blackberrysetupwizard.h b/src/plugins/qnx/blackberrysetupwizard.h index a224ed6487..a1e39873f5 100644 --- a/src/plugins/qnx/blackberrysetupwizard.h +++ b/src/plugins/qnx/blackberrysetupwizard.h @@ -69,6 +69,7 @@ public slots: signals: void stepFinished(); + void ndkTargetsUpdated(); private slots: void processNextStep(); diff --git a/src/plugins/qnx/blackberrysetupwizardpages.cpp b/src/plugins/qnx/blackberrysetupwizardpages.cpp index 5d088de19e..fd66057119 100644 --- a/src/plugins/qnx/blackberrysetupwizardpages.cpp +++ b/src/plugins/qnx/blackberrysetupwizardpages.cpp @@ -87,6 +87,7 @@ BlackBerrySetupWizardNdkPage::BlackBerrySetupWizardNdkPage(QWidget *parent) : m_widget->setWizardMessageVisible(false); connect(m_widget, SIGNAL(targetsUpdated()), this, SIGNAL(completeChanged())); + connect(m_widget, SIGNAL(targetsUpdated()), this, SIGNAL(targetsUpdated())); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(m_widget); diff --git a/src/plugins/qnx/blackberrysetupwizardpages.h b/src/plugins/qnx/blackberrysetupwizardpages.h index ba586a3da4..75a00524e1 100644 --- a/src/plugins/qnx/blackberrysetupwizardpages.h +++ b/src/plugins/qnx/blackberrysetupwizardpages.h @@ -70,6 +70,9 @@ public: bool isComplete() const; +signals: + void targetsUpdated(); + private: BlackBerryNDKSettingsWidget *m_widget; }; diff --git a/src/plugins/qnx/blackberrysigningutils.cpp b/src/plugins/qnx/blackberrysigningutils.cpp index 9905d7515c..f9fb2b8cf0 100644 --- a/src/plugins/qnx/blackberrysigningutils.cpp +++ b/src/plugins/qnx/blackberrysigningutils.cpp @@ -82,18 +82,24 @@ bool BlackBerrySigningUtils::hasDefaultCertificate() return keystore.exists(); } -QString BlackBerrySigningUtils::cskPassword() +QString BlackBerrySigningUtils::cskPassword(QWidget *passwordPromptParent, bool *ok) { if (m_cskPassword.isEmpty()) - m_cskPassword = promptPassword(tr("Please provide your bbidtoken.csk PIN.")); + m_cskPassword = promptPassword(tr("Please provide your bbidtoken.csk PIN."), passwordPromptParent, ok); + else if (ok) + *ok = true; return m_cskPassword; } -QString BlackBerrySigningUtils::certificatePassword() +QString BlackBerrySigningUtils::certificatePassword(QWidget *passwordPromptParent, bool *ok) { - if (m_certificatePassword.isEmpty()) - m_certificatePassword = promptPassword(tr("Please enter your certificate password.")); + if (m_certificatePassword.isEmpty()) { + m_certificatePassword = + promptPassword(tr("Please enter your certificate password."), passwordPromptParent, ok); + } else if (ok) { + *ok = true; + } return m_certificatePassword; } @@ -103,14 +109,19 @@ const BlackBerryCertificate * BlackBerrySigningUtils::defaultCertificate() const return m_defaultCertificate; } -void BlackBerrySigningUtils::openDefaultCertificate() +void BlackBerrySigningUtils::openDefaultCertificate(QWidget *passwordPromptParent) { if (m_defaultCertificate) { emit defaultCertificateLoaded(BlackBerryCertificate::Success); return; } - const QString password = certificatePassword(); + bool ok; + const QString password = certificatePassword(passwordPromptParent, &ok); + + // action has been canceled + if (!ok) + return; BlackBerryConfigurationManager &configManager = BlackBerryConfigurationManager::instance(); @@ -165,16 +176,24 @@ void BlackBerrySigningUtils::certificateLoaded(int status) emit defaultCertificateLoaded(status); } -QString BlackBerrySigningUtils::promptPassword(const QString &message) const +QString BlackBerrySigningUtils::promptPassword(const QString &message, + QWidget *dialogParent, bool *ok) const { - QInputDialog dialog; + QInputDialog dialog(dialogParent); dialog.setWindowTitle(tr("Qt Creator")); dialog.setInputMode(QInputDialog::TextInput); dialog.setLabelText(message); dialog.setTextEchoMode(QLineEdit::Password); - if (dialog.exec() == QDialog::Rejected) + if (dialog.exec() == QDialog::Rejected) { + if (ok) + *ok = false; + return QString(); + } + + if (ok) + *ok = true; return dialog.textValue(); } diff --git a/src/plugins/qnx/blackberrysigningutils.h b/src/plugins/qnx/blackberrysigningutils.h index c18f202245..3cf139162e 100644 --- a/src/plugins/qnx/blackberrysigningutils.h +++ b/src/plugins/qnx/blackberrysigningutils.h @@ -55,12 +55,12 @@ public: bool hasLegacyKeys(); bool hasDefaultCertificate(); - QString cskPassword(); - QString certificatePassword(); + QString cskPassword(QWidget *passwordPromptParent = 0, bool *ok = 0); + QString certificatePassword(QWidget *passwordPromptParent = 0, bool *ok = 0); const BlackBerryCertificate *defaultCertificate() const; - void openDefaultCertificate(); + void openDefaultCertificate(QWidget *passwordPromptParent = 0); void setDefaultCertificate(BlackBerryCertificate *certificate); void clearCskPassword(); void clearCertificatePassword(); @@ -77,7 +77,7 @@ private: BlackBerrySigningUtils(QObject *parent = 0); - QString promptPassword(const QString &message) const; + QString promptPassword(const QString &message, QWidget *dialogParent = 0, bool *ok = 0) const; BlackBerryCertificate *m_defaultCertificate; diff --git a/src/plugins/qnx/blackberryversionnumber.cpp b/src/plugins/qnx/blackberryversionnumber.cpp new file mode 100644 index 0000000000..4d198de3f6 --- /dev/null +++ b/src/plugins/qnx/blackberryversionnumber.cpp @@ -0,0 +1,125 @@ +/************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** +** Contact: BlackBerry (qt@blackberry.com) +** Contact: KDAB (info@kdab.com) +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "blackberryversionnumber.h" + +#include <QDir> + +namespace Qnx { +namespace Internal { + +static const char NONDIGIT_SEGMENT_REGEXP[] = "(?<=\\d)(?=\\D)|(?<=\\D)(?=\\d)"; + +BlackBerryVersionNumber::BlackBerryVersionNumber(const QStringList &listNumber) + : m_segments(listNumber) +{ +} + +BlackBerryVersionNumber::BlackBerryVersionNumber(const QString &version) +{ + m_segments = version.split(QLatin1Char('.')); +} + +BlackBerryVersionNumber::BlackBerryVersionNumber() +{ +} + +QString BlackBerryVersionNumber::toString() const +{ + return m_segments.join(QLatin1String(".")); +} + +bool BlackBerryVersionNumber::operator >(const BlackBerryVersionNumber &b) const +{ + int minSize = size() > b.size() ? b.size() : size(); + for (int i = 0; i < minSize; i++) { + if (segment(i) != b.segment(i)) { + // Segment can contain digits and non digits expressions + QStringList aParts = segment(i).split(QLatin1String(NONDIGIT_SEGMENT_REGEXP)); + QStringList bParts = b.segment(i).split(QLatin1String(NONDIGIT_SEGMENT_REGEXP)); + + int minPartSize = aParts.length() > bParts.length() ? bParts.length() : aParts.length(); + for (int j = 0; j < minPartSize; j++) { + bool aOk = true; + bool bOk = true; + int aInt = aParts[j].toInt(&aOk); + int bInt = bParts[j].toInt(&bOk); + + if (aOk && bOk) + return aInt > bInt; + + return aParts[j].compare(bParts[j]) > 0; + } + } + } + + return false; +} + +QString BlackBerryVersionNumber::segment(int index) const +{ + if (index < m_segments.length()) + return m_segments.at(index); + + return QString(); +} + +BlackBerryVersionNumber BlackBerryVersionNumber::fromNdkEnvFileName(const QString &ndkEnvFileName) +{ + return fromFileName(ndkEnvFileName, QRegExp(QLatin1String("^bbndk-env_(.*)$"))); +} + +BlackBerryVersionNumber BlackBerryVersionNumber::fromTargetName(const QString &targetName) +{ + return fromFileName(targetName, QRegExp(QLatin1String("^target_(.*)$"))); +} + +BlackBerryVersionNumber BlackBerryVersionNumber::fromFileName(const QString &fileName, const QRegExp ®Exp) +{ + QStringList segments; + if (regExp.exactMatch(fileName) && regExp.captureCount() == 1) + segments << regExp.cap(1).split(QLatin1Char('_')); + + return BlackBerryVersionNumber(segments); +} + +int BlackBerryVersionNumber::size() const +{ + return m_segments.length(); +} + +bool BlackBerryVersionNumber::isEmpty() const +{ + return m_segments.isEmpty(); +} + +} // namespace Internal +} // namespace Qnx diff --git a/src/plugins/debugger/lldblib/lldboptionspage.h b/src/plugins/qnx/blackberryversionnumber.h index 81ebfaf28c..738275fa50 100644 --- a/src/plugins/debugger/lldblib/lldboptionspage.h +++ b/src/plugins/qnx/blackberryversionnumber.h @@ -1,7 +1,9 @@ -/**************************************************************************** +/************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** +** Contact: BlackBerry (qt@blackberry.com) +** Contact: KDAB (info@kdab.com) ** ** This file is part of Qt Creator. ** @@ -27,54 +29,36 @@ ** ****************************************************************************/ -#ifndef LLDBOPTIONSPAGE_H -#define LLDBOPTIONSPAGE_H - -#include <coreplugin/dialogs/ioptionspage.h> -#include "ui_lldboptionspagewidget.h" +#ifndef BLACKBERRY_VERSION_NUMBER_H +#define BLACKBERRY_VERSION_NUMBER_H -#include <QWidget> -#include <QPointer> -#include <QSharedPointer> -#include <QSettings> +#include <QStringList> -namespace Debugger { +namespace Qnx { namespace Internal { - -class LldbOptionsPageWidget : public QWidget +class BlackBerryVersionNumber { - Q_OBJECT - public: - explicit LldbOptionsPageWidget(QWidget *parent, QSettings *s); - -public slots: - void save(); - void load(); + BlackBerryVersionNumber(const QStringList &segments); + BlackBerryVersionNumber(const QString &version); + BlackBerryVersionNumber(); -private: - Ui::LldbOptionsPageWidget m_ui; - QSettings *s; -}; + int size() const; + bool isEmpty() const; + QString segment(int index) const; + QString toString() const; -class LldbOptionsPage : public Core::IOptionsPage -{ - Q_OBJECT - -public: - LldbOptionsPage(); + static BlackBerryVersionNumber fromNdkEnvFileName(const QString &ndkEnvFileName); + static BlackBerryVersionNumber fromTargetName(const QString &targetName); + static BlackBerryVersionNumber fromFileName(const QString &fileName, const QRegExp ®Exp); - // IOptionsPage - QWidget *createPage(QWidget *parent); - void apply(); - void finish(); - bool matches(const QString &) const; + bool operator >(const BlackBerryVersionNumber &b) const; private: - QPointer<LldbOptionsPageWidget> m_widget; + QStringList m_segments; }; } // namespace Internal -} // namespace Debugger +} // namespace Qnx -#endif // LLDBOPTIONSPAGE_H +#endif // VERSIONNUMBER_H diff --git a/src/plugins/qnx/qnx.pro b/src/plugins/qnx/qnx.pro index 511888f146..25df0bf0fa 100644 --- a/src/plugins/qnx/qnx.pro +++ b/src/plugins/qnx/qnx.pro @@ -98,7 +98,8 @@ SOURCES += qnxplugin.cpp \ qnxdeviceprocesssignaloperation.cpp \ qnxdeviceprocesslist.cpp \ qnxtoolchain.cpp \ - slog2inforunner.cpp + slog2inforunner.cpp \ + blackberryversionnumber.cpp HEADERS += qnxplugin.h\ qnxconstants.h \ @@ -196,7 +197,8 @@ HEADERS += qnxplugin.h\ qnxdeviceprocesssignaloperation.h \ qnxdeviceprocesslist.h \ qnxtoolchain.h \ - slog2inforunner.h + slog2inforunner.h \ + blackberryversionnumber.h FORMS += \ diff --git a/src/plugins/qnx/qnx.qbs b/src/plugins/qnx/qnx.qbs index 4be75bb4df..a425414e93 100644 --- a/src/plugins/qnx/qnx.qbs +++ b/src/plugins/qnx/qnx.qbs @@ -185,6 +185,8 @@ QtcPlugin { "blackberrysetupwizardfinishpage.ui", "blackberrysigningutils.cpp", "blackberrysigningutils.h", + "blackberryversionnumber.cpp", + "blackberryversionnumber.h", "pathchooserdelegate.cpp", "pathchooserdelegate.h", "qnxtoolchain.cpp", diff --git a/src/plugins/qnx/qnxutils.cpp b/src/plugins/qnx/qnxutils.cpp index c15696ad8b..600c587406 100644 --- a/src/plugins/qnx/qnxutils.cpp +++ b/src/plugins/qnx/qnxutils.cpp @@ -287,8 +287,12 @@ QString QnxUtils::qdeInstallProcess(const QString &ndkPath, const QString &optio if (installerPath.isEmpty()) return QString(); - return QString::fromLatin1("%1 -nosplash -application com.qnx.tools.ide.sdk.manager.core.SDKInstallerApplication " - "%2 %3 -vmargs -Dosgi.console=:none").arg(installerPath, option, version); + const QDir pluginDir(ndkPath + QLatin1String("/plugins")); + const QStringList installerPlugins = pluginDir.entryList(QStringList() << QLatin1String("com.qnx.tools.ide.sdk.installer.app_*.jar")); + const QString installerApplication = installerPlugins.size() >= 1 ? QLatin1String("com.qnx.tools.ide.sdk.installer.app.SDKInstallerApplication") + : QLatin1String("com.qnx.tools.ide.sdk.manager.core.SDKInstallerApplication"); + return QString::fromLatin1("%1 -nosplash -application %2 " + "%3 %4 -vmargs -Dosgi.console=:none").arg(installerPath, installerApplication, option, version); } QList<Utils::EnvironmentItem> QnxUtils::qnxEnvironment(const QString &sdkPath) diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 451d4dcb92..e656693009 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -218,7 +218,7 @@ QString BaseQtVersion::defaultDisplayName(const QString &versionString, const Fi && dirName.compare(QLatin1String("qt"), Qt::CaseInsensitive)) { break; } - } while (dir.cdUp()); + } while (!dir.isRoot() && dir.cdUp()); } return fromPath ? diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index a8e887f473..ce7e361a0f 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -181,16 +181,19 @@ public: // gets called by declarative in separate thread QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) { - Q_UNUSED(size) QMutexLocker lock(&m_mutex); QUrl url = QUrl::fromEncoded(id.toLatin1()); - if (!m_fetcher.asynchronousFetchData(url)) - return QImage(); - if (m_fetcher.data().isEmpty()) + if (!m_fetcher.asynchronousFetchData(url) || m_fetcher.data().isEmpty()) { + if (size) { + size->setWidth(0); + size->setHeight(0); + } return QImage(); + } + QByteArray data = m_fetcher.data(); QBuffer imgBuffer(&data); imgBuffer.open(QIODevice::ReadOnly); @@ -198,7 +201,11 @@ public: QImage img = reader.read(); m_fetcher.clearData(); - return ScreenshotCropper::croppedImage(img, id, requestedSize); + img = ScreenshotCropper::croppedImage(img, id, requestedSize); + if (size) + *size = img.size(); + return img; + } private: Fetcher m_fetcher; diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp index 34959f4a1c..ac04ba6168 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp @@ -183,6 +183,7 @@ void GenericLinuxDeviceConfigurationWidget::initGui() m_ui->portsWarningLabel->setToolTip(QLatin1String("<font color=\"red\">") + tr("You will need at least one port.") + QLatin1String("</font>")); m_ui->keyFileLineEdit->setExpectedKind(PathChooser::File); + m_ui->keyFileLineEdit->setHistoryCompleter(QLatin1String("Ssh.KeyFile.History")); m_ui->keyFileLineEdit->lineEdit()->setMinimumWidth(0); QRegExpValidator * const portsValidator = new QRegExpValidator(QRegExp(PortList::regularExpression()), this); diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp index e23a3ff903..110a4076ac 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizardpages.cpp @@ -59,6 +59,7 @@ GenericLinuxDeviceConfigurationWizardSetupPage::GenericLinuxDeviceConfigurationW setTitle(tr("Connection")); setSubTitle(QLatin1String(" ")); // For Qt bug (background color) d->ui.privateKeyPathChooser->setExpectedKind(PathChooser::File); + d->ui.privateKeyPathChooser->setHistoryCompleter(QLatin1String("Ssh.KeyFile.History")); d->ui.privateKeyPathChooser->setPromptDialogTitle(tr("Choose a Private Key File")); connect(d->ui.nameLineEdit, SIGNAL(textChanged(QString)), SIGNAL(completeChanged())); connect(d->ui.hostNameLineEdit, SIGNAL(textChanged(QString)), SIGNAL(completeChanged())); diff --git a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp index 6372b8cae0..15c4614924 100644 --- a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp +++ b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp @@ -121,6 +121,7 @@ RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Ru } QTC_ASSERT(false, return 0); + return 0; } } // namespace Internal diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 8eb8db8613..2ccfa4cb9c 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -1175,7 +1175,7 @@ bool SubversionPlugin::managesDirectory(const QString &directory, QString *topLe * furthest parent containing ".svn/wc.db". Need to check for furthest parent as closer * parents may be svn:externals. */ QDir parentDir = dir; - while (parentDir.cdUp()) { + while (!parentDir.isRoot() && parentDir.cdUp()) { if (checkSVNSubDir(parentDir, QLatin1String("wc.db"))) { if (topLevel) *topLevel = parentDir.absolutePath(); @@ -1191,7 +1191,9 @@ bool SubversionPlugin::managesDirectory(const QString &directory, QString *topLe if (topLevel) { QDir lastDirectory = dir; - for (parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) { + for (parentDir = lastDirectory; + !parentDir.isRoot() && parentDir.cdUp(); + lastDirectory = parentDir) { if (!checkSVNSubDir(parentDir)) { *topLevel = lastDirectory.absolutePath(); break; diff --git a/src/plugins/texteditor/basetextdocument.cpp b/src/plugins/texteditor/basetextdocument.cpp index 239041311c..adf2e2364d 100644 --- a/src/plugins/texteditor/basetextdocument.cpp +++ b/src/plugins/texteditor/basetextdocument.cpp @@ -92,7 +92,7 @@ BaseTextDocument::~BaseTextDocument() delete d; } -QString BaseTextDocument::contents() const +QString BaseTextDocument::plainText() const { return document()->toPlainText(); } @@ -195,7 +195,7 @@ SyntaxHighlighter *BaseTextDocument::syntaxHighlighter() const return d->m_highlighter; } -ITextMarkable *BaseTextDocument::documentMarker() const +ITextMarkable *BaseTextDocument::markableInterface() const { BaseTextDocumentLayout *documentLayout = qobject_cast<BaseTextDocumentLayout *>(d->m_document->documentLayout()); diff --git a/src/plugins/texteditor/basetextdocument.h b/src/plugins/texteditor/basetextdocument.h index a8f8f2ca7a..1a0a8ff3f5 100644 --- a/src/plugins/texteditor/basetextdocument.h +++ b/src/plugins/texteditor/basetextdocument.h @@ -58,7 +58,7 @@ public: virtual ~BaseTextDocument(); // ITextEditorDocument - QString contents() const; + QString plainText() const; QString textAt(int pos, int length) const; QChar characterAt(int pos) const; @@ -72,7 +72,7 @@ public: const TabSettings &tabSettings() const; const ExtraEncodingSettings &extraEncodingSettings() const; - ITextMarkable *documentMarker() const; + ITextMarkable *markableInterface() const; // IDocument implementation. bool save(QString *errorString, const QString &fileName, bool autoSave); diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 63f2a3d719..268f265f2e 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -486,11 +486,6 @@ int BaseTextEditorWidgetPrivate::visualIndent(const QTextBlock &block) const return 0; } -ITextMarkable *BaseTextEditorWidget::markableInterface() const -{ - return baseTextDocument()->documentMarker(); -} - BaseTextEditor *BaseTextEditorWidget::editor() const { if (!d->m_editor) { @@ -3863,8 +3858,6 @@ void BaseTextEditorWidget::drawFoldingMarker(QPainter *painter, const QPalette & bool active, bool hovered) const { - Q_UNUSED(active) - Q_UNUSED(hovered) QStyle *s = style(); if (ManhattanStyle *ms = qobject_cast<ManhattanStyle*>(s)) s = ms->baseStyle(); diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index 6994a90e97..9ce78d7783 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -148,7 +148,6 @@ public: void convertPosition(int pos, int *line, int *column) const; BaseTextEditor *editor() const; - ITextMarkable *markableInterface() const; void print(QPrinter *); @@ -624,8 +623,6 @@ public: QString selectedText() const; - ITextMarkable *markableInterface() { return m_editorWidget->markableInterface(); } - QString contextHelpId() const; // from IContext // ITextEditor diff --git a/src/plugins/texteditor/basetextmark.cpp b/src/plugins/texteditor/basetextmark.cpp index dd5832a7bb..f0f045dd4a 100644 --- a/src/plugins/texteditor/basetextmark.cpp +++ b/src/plugins/texteditor/basetextmark.cpp @@ -60,14 +60,11 @@ void BaseTextMarkRegistry::add(BaseTextMark *mark) { m_marks[FileName::fromString(mark->fileName())].insert(mark); DocumentModel *documentModel = EditorManager::documentModel(); - IDocument *document = documentModel->documentForFilePath(mark->fileName()); + ITextEditorDocument *document + = qobject_cast<ITextEditorDocument*>(documentModel->documentForFilePath(mark->fileName())); if (!document) return; - // TODO: markableInterface should be moved to ITextEditorDocument - if (ITextEditor *textEditor - = qobject_cast<ITextEditor *>(documentModel->editorsForDocument(document).first())) { - textEditor->markableInterface()->addMark(mark); - } + document->markableInterface()->addMark(mark); } bool BaseTextMarkRegistry::remove(BaseTextMark *mark) @@ -77,16 +74,14 @@ bool BaseTextMarkRegistry::remove(BaseTextMark *mark) void BaseTextMarkRegistry::editorOpened(Core::IEditor *editor) { - ITextEditor *textEditor = qobject_cast<ITextEditor *>(editor); - if (!textEditor) + ITextEditorDocument *document = qobject_cast<ITextEditorDocument *>(editor ? editor->document() : 0); + if (!document) return; - if (!m_marks.contains(FileName::fromString(editor->document()->filePath()))) + if (!m_marks.contains(FileName::fromString(document->filePath()))) return; - foreach (BaseTextMark *mark, m_marks.value(FileName::fromString(editor->document()->filePath()))) { - ITextMarkable *markableInterface = textEditor->markableInterface(); - markableInterface->addMark(mark); - } + foreach (BaseTextMark *mark, m_marks.value(FileName::fromString(document->filePath()))) + document->markableInterface()->addMark(mark); } void BaseTextMarkRegistry::documentRenamed(IDocument *document, const @@ -102,7 +97,7 @@ void BaseTextMarkRegistry::documentRenamed(IDocument *document, const return; QSet<BaseTextMark *> toBeMoved; - foreach (ITextMark *mark, baseTextDocument->documentMarker()->marks()) + foreach (ITextMark *mark, baseTextDocument->markableInterface()->marks()) if (BaseTextMark *baseTextMark = dynamic_cast<BaseTextMark *>(mark)) toBeMoved.insert(baseTextMark); diff --git a/src/plugins/texteditor/behaviorsettingswidget.ui b/src/plugins/texteditor/behaviorsettingswidget.ui index 324313b74a..5aeb0f37c5 100644 --- a/src/plugins/texteditor/behaviorsettingswidget.ui +++ b/src/plugins/texteditor/behaviorsettingswidget.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>802</width> - <height>416</height> + <height>441</height> </rect> </property> <layout class="QHBoxLayout" name="horizontalLayout"> @@ -207,7 +207,7 @@ Specifies how backspace interacts with indentation. </sizepolicy> </property> <property name="toolTip"> - <string>Clean whitespace in entire document instead of only for changed parts.</string> + <string>Cleans whitespace in entire document instead of only for changed parts.</string> </property> <property name="text"> <string>In entire &document</string> @@ -220,7 +220,7 @@ Specifies how backspace interacts with indentation. <bool>false</bool> </property> <property name="toolTip"> - <string>Correct leading whitespace according to tab settings.</string> + <string>Corrects leading whitespace according to tab settings.</string> </property> <property name="text"> <string>Clean indentation</string> @@ -230,7 +230,7 @@ Specifies how backspace interacts with indentation. <item row="3" column="0" colspan="2"> <widget class="QCheckBox" name="addFinalNewLine"> <property name="toolTip"> - <string>Always write a newline character at the end of the file.</string> + <string>Always writes a newline character at the end of the file.</string> </property> <property name="text"> <string>&Ensure newline at end of file</string> diff --git a/src/plugins/texteditor/codestylepool.cpp b/src/plugins/texteditor/codestylepool.cpp index 009b1e5454..5b5a7132d3 100644 --- a/src/plugins/texteditor/codestylepool.cpp +++ b/src/plugins/texteditor/codestylepool.cpp @@ -290,6 +290,6 @@ void CodeStylePool::exportCodeStyle(const Utils::FileName &fileName, ICodeStyleP tmp.insert(QLatin1String(displayNameKey), codeStyle->displayName()); tmp.insert(QLatin1String(codeStyleDataKey), map); Utils::PersistentSettingsWriter writer(fileName, QLatin1String(codeStyleDocKey)); - writer.save(tmp, 0); + writer.save(tmp, Core::ICore::mainWindow()); } diff --git a/src/plugins/texteditor/generichighlighter/highlighter.cpp b/src/plugins/texteditor/generichighlighter/highlighter.cpp index a894b2f092..3a195d37e2 100644 --- a/src/plugins/texteditor/generichighlighter/highlighter.cpp +++ b/src/plugins/texteditor/generichighlighter/highlighter.cpp @@ -50,6 +50,30 @@ namespace { static const QLatin1Char kHash('#'); } +class HighlighterCodeFormatterData : public CodeFormatterData +{ +public: + HighlighterCodeFormatterData() : m_foldingIndentDelta(0), m_originalObservableState(-1) {} + ~HighlighterCodeFormatterData() {} + int m_foldingIndentDelta; + int m_originalObservableState; + QStack<QString> m_foldingRegions; + QSharedPointer<Internal::Context> m_contextToContinue; +}; + +HighlighterCodeFormatterData *formatterData(const QTextBlock &block) +{ + HighlighterCodeFormatterData *data = 0; + if (TextBlockUserData *userData = BaseTextDocumentLayout::userData(block)) { + data = static_cast<HighlighterCodeFormatterData *>(userData->codeFormatterData()); + if (!data) { + data = new HighlighterCodeFormatterData; + userData->setCodeFormatterData(data); + } + } + return data; +} + Highlighter::Highlighter(QTextDocument *parent) : TextEditor::SyntaxHighlighter(parent), m_regionDepth(0), @@ -85,12 +109,6 @@ Highlighter::Highlighter(QTextDocument *parent) : Highlighter::~Highlighter() {} -Highlighter::BlockData::BlockData() : m_foldingIndentDelta(0), m_originalObservableState(-1) -{} - -Highlighter::BlockData::~BlockData() -{} - // Mapping from Kate format strings to format ids. struct KateFormatMap { @@ -135,8 +153,6 @@ void Highlighter::highlightBlock(const QString &text) { if (!m_defaultContext.isNull() && !m_isBroken) { try { - if (!currentBlockUserData()) - initializeBlockData(); setupDataForBlock(text); handleContextChange(m_currentContext->lineBeginContext(), @@ -188,8 +204,8 @@ void Highlighter::setupDataForBlock(const QString &text) else setupFromPersistent(); - blockData(currentBlockUserData())->m_foldingRegions = - blockData(currentBlock().previous().userData())->m_foldingRegions; + formatterData(currentBlock())->m_foldingRegions = + formatterData(currentBlock().previous())->m_foldingRegions; } assignCurrentContext(); @@ -204,7 +220,7 @@ void Highlighter::setupDefault() void Highlighter::setupFromWillContinue() { - BlockData *previousData = blockData(currentBlock().previous().userData()); + HighlighterCodeFormatterData *previousData = formatterData(currentBlock().previous()); if (previousData->m_originalObservableState == Default || previousData->m_originalObservableState == -1) { m_contexts.push_back(previousData->m_contextToContinue); @@ -212,7 +228,7 @@ void Highlighter::setupFromWillContinue() pushContextSequence(previousData->m_originalObservableState); } - BlockData *data = blockData(currentBlock().userData()); + HighlighterCodeFormatterData *data = formatterData(currentBlock()); data->m_originalObservableState = previousData->m_originalObservableState; if (currentBlockState() == -1 || extractObservableState(currentBlockState()) == Default) @@ -221,7 +237,7 @@ void Highlighter::setupFromWillContinue() void Highlighter::setupFromContinued() { - BlockData *previousData = blockData(currentBlock().previous().userData()); + HighlighterCodeFormatterData *previousData = formatterData(currentBlock().previous()); Q_ASSERT(previousData->m_originalObservableState != WillContinue && previousData->m_originalObservableState != Continued); @@ -264,19 +280,19 @@ void Highlighter::iterateThroughRules(const QString &text, if (!m_indentationBasedFolding) { if (!rule->beginRegion().isEmpty()) { - blockData(currentBlockUserData())->m_foldingRegions.push(rule->beginRegion()); + formatterData(currentBlock())->m_foldingRegions.push(rule->beginRegion()); ++m_regionDepth; if (progress->isOpeningBraceMatchAtFirstNonSpace()) - ++blockData(currentBlockUserData())->m_foldingIndentDelta; + ++formatterData(currentBlock())->m_foldingIndentDelta; } if (!rule->endRegion().isEmpty()) { QStack<QString> *currentRegions = - &blockData(currentBlockUserData())->m_foldingRegions; + &formatterData(currentBlock())->m_foldingRegions; if (!currentRegions->isEmpty() && rule->endRegion() == currentRegions->top()) { currentRegions->pop(); --m_regionDepth; if (progress->isClosingBraceMatchAtNonEnd()) - --blockData(currentBlockUserData())->m_foldingIndentDelta; + --formatterData(currentBlock())->m_foldingIndentDelta; } } progress->clearBracesMatches(); @@ -442,10 +458,10 @@ void Highlighter::applyFormat(int offset, void Highlighter::createWillContinueBlock() { - BlockData *data = blockData(currentBlockUserData()); + HighlighterCodeFormatterData *data = formatterData(currentBlock()); const int currentObservableState = extractObservableState(currentBlockState()); if (currentObservableState == Continued) { - BlockData *previousData = blockData(currentBlock().previous().userData()); + HighlighterCodeFormatterData *previousData = formatterData(currentBlock().previous()); data->m_originalObservableState = previousData->m_originalObservableState; } else if (currentObservableState != WillContinue) { data->m_originalObservableState = currentObservableState; @@ -464,7 +480,7 @@ void Highlighter::analyseConsistencyOfWillContinueBlock(const QString &text) } if (text.length() == 0 || text.at(text.length() - 1) != kBackSlash) { - BlockData *data = blockData(currentBlockUserData()); + HighlighterCodeFormatterData *data = formatterData(currentBlock()); data->m_contextToContinue.clear(); setCurrentBlockState(computeState(data->m_originalObservableState)); } @@ -503,18 +519,6 @@ QString Highlighter::currentContextSequence() const return sequence; } -Highlighter::BlockData *Highlighter::initializeBlockData() -{ - BlockData *data = new BlockData; - setCurrentBlockUserData(data); - return data; -} - -Highlighter::BlockData *Highlighter::blockData(QTextBlockUserData *userData) -{ - return static_cast<BlockData *>(userData); -} - void Highlighter::pushDynamicContext(const QSharedPointer<Context> &baseContext) { // A dynamic context is created from another context which serves as its basis. Then, @@ -556,26 +560,27 @@ int Highlighter::computeState(const int observableState) const void Highlighter::applyRegionBasedFolding() const { int folding = 0; - BlockData *data = blockData(currentBlockUserData()); - BlockData *previousData = blockData(currentBlock().previous().userData()); + TextBlockUserData *currentBlockUserData = BaseTextDocumentLayout::userData(currentBlock()); + HighlighterCodeFormatterData *data = formatterData(currentBlock()); + HighlighterCodeFormatterData *previousData = formatterData(currentBlock().previous()); if (previousData) { folding = extractRegionDepth(previousBlockState()); if (data->m_foldingIndentDelta != 0) { folding += data->m_foldingIndentDelta; if (data->m_foldingIndentDelta > 0) - data->setFoldingStartIncluded(true); + currentBlockUserData->setFoldingStartIncluded(true); else - previousData->setFoldingEndIncluded(false); + BaseTextDocumentLayout::userData(currentBlock().previous())->setFoldingEndIncluded(false); data->m_foldingIndentDelta = 0; } } - data->setFoldingEndIncluded(true); - data->setFoldingIndent(folding); + currentBlockUserData->setFoldingEndIncluded(true); + currentBlockUserData->setFoldingIndent(folding); } void Highlighter::applyIndentationBasedFolding(const QString &text) const { - BlockData *data = blockData(currentBlockUserData()); + TextBlockUserData *data = BaseTextDocumentLayout::userData(currentBlock()); data->setFoldingEndIncluded(true); // If this line is empty, check its neighbours. They all might be part of the same block. diff --git a/src/plugins/texteditor/generichighlighter/highlighter.h b/src/plugins/texteditor/generichighlighter/highlighter.h index ef0498036a..caf7275449 100644 --- a/src/plugins/texteditor/generichighlighter/highlighter.h +++ b/src/plugins/texteditor/generichighlighter/highlighter.h @@ -135,18 +135,7 @@ private: void applyIndentationBasedFolding(const QString &text) const; int neighbouringNonEmptyBlockIndent(QTextBlock block, const bool previous) const; - struct BlockData : TextBlockUserData - { - BlockData(); - virtual ~BlockData(); - - int m_foldingIndentDelta; - int m_originalObservableState; - QStack<QString> m_foldingRegions; - QSharedPointer<Internal::Context> m_contextToContinue; - }; - BlockData *initializeBlockData(); - static BlockData *blockData(QTextBlockUserData *userData); + static TextBlockUserData *blockData(QTextBlockUserData *userData); // Block states are composed by the region depth (used for code folding) and what I call // observable states. Observable states occupy the 12 least significant bits. They might have diff --git a/src/plugins/texteditor/generichighlighter/highlightersettingspage.cpp b/src/plugins/texteditor/generichighlighter/highlightersettingspage.cpp index c04a5d72e9..637a580434 100644 --- a/src/plugins/texteditor/generichighlighter/highlightersettingspage.cpp +++ b/src/plugins/texteditor/generichighlighter/highlightersettingspage.cpp @@ -94,9 +94,11 @@ QWidget *HighlighterSettingsPage::createPage(QWidget *parent) m_d->m_page = new Ui::HighlighterSettingsPage; m_d->m_page->setupUi(w); m_d->m_page->definitionFilesPath->setExpectedKind(Utils::PathChooser::ExistingDirectory); + m_d->m_page->definitionFilesPath->setHistoryCompleter(QLatin1String("TextEditor.Highlighter.History")); m_d->m_page->definitionFilesPath->addButton(tr("Download Definitions..."), this, SLOT(requestAvailableDefinitionsMetaData())); m_d->m_page->fallbackDefinitionFilesPath->setExpectedKind(Utils::PathChooser::ExistingDirectory); + m_d->m_page->fallbackDefinitionFilesPath->setHistoryCompleter(QLatin1String("TextEditor.Highlighter.History")); m_d->m_page->fallbackDefinitionFilesPath->addButton(tr("Autodetect"), this, SLOT(resetDefinitionsLocation())); diff --git a/src/plugins/texteditor/itexteditor.cpp b/src/plugins/texteditor/itexteditor.cpp index ab2b80b9b2..67a511033a 100644 --- a/src/plugins/texteditor/itexteditor.cpp +++ b/src/plugins/texteditor/itexteditor.cpp @@ -46,7 +46,7 @@ QMap<QString, QString> ITextEditor::openedTextDocumentContents() if (!textEditorDocument) continue; QString fileName = textEditorDocument->filePath(); - workingCopy[fileName] = textEditorDocument->contents(); + workingCopy[fileName] = textEditorDocument->plainText(); } return workingCopy; } diff --git a/src/plugins/texteditor/itexteditor.h b/src/plugins/texteditor/itexteditor.h index 2fa63d34c1..a3ac48bd48 100644 --- a/src/plugins/texteditor/itexteditor.h +++ b/src/plugins/texteditor/itexteditor.h @@ -81,9 +81,11 @@ class TEXTEDITOR_EXPORT ITextEditorDocument : public Core::TextDocument public: explicit ITextEditorDocument(QObject *parent = 0); - virtual QString contents() const = 0; + virtual QString plainText() const = 0; virtual QString textAt(int pos, int length) const = 0; virtual QChar characterAt(int pos) const = 0; + + virtual ITextMarkable *markableInterface() const = 0; }; class TEXTEDITOR_EXPORT ITextEditor : public Core::IEditor @@ -126,8 +128,6 @@ public: /*! Selects text between current cursor position and \a toPos. */ virtual void select(int toPos) = 0; - virtual ITextMarkable *markableInterface() = 0; - virtual const Utils::CommentDefinition* commentDefinition() const = 0; static QMap<QString, QString> openedTextDocumentContents(); diff --git a/src/plugins/todo/optionsdialog.ui b/src/plugins/todo/optionsdialog.ui index d8b4f6d963..b07912b5e9 100644 --- a/src/plugins/todo/optionsdialog.ui +++ b/src/plugins/todo/optionsdialog.ui @@ -87,14 +87,14 @@ <bool>true</bool> </property> <property name="text"> - <string>Scan in the whole project</string> + <string>Scan the whole active project</string> </property> </widget> </item> <item> <widget class="QRadioButton" name="scanInCurrentFileRadioButton"> <property name="text"> - <string>Scan in the current opened file</string> + <string>Scan only the currently edited document</string> </property> <property name="checked"> <bool>true</bool> diff --git a/src/plugins/todo/todooutputpane.cpp b/src/plugins/todo/todooutputpane.cpp index 6efa68fafd..578f935b54 100755 --- a/src/plugins/todo/todooutputpane.cpp +++ b/src/plugins/todo/todooutputpane.cpp @@ -188,13 +188,13 @@ void TodoOutputPane::createScopeButtons() { m_currentFileButton = new QToolButton(); m_currentFileButton->setCheckable(true); - m_currentFileButton->setText(tr("Current File")); - m_currentFileButton->setToolTip(tr("Scan in the current opened file")); + m_currentFileButton->setText(tr("Current Document")); + m_currentFileButton->setToolTip(tr("Scan only the currently edited document.")); m_wholeProjectButton = new QToolButton(); m_wholeProjectButton->setCheckable(true); - m_wholeProjectButton->setText(tr("Whole Project")); - m_wholeProjectButton->setToolTip(tr("Scan in the whole project")); + m_wholeProjectButton->setText(tr("Active Project")); + m_wholeProjectButton->setToolTip(tr("Scan the whole active project.")); m_scopeButtons = new QButtonGroup(); m_scopeButtons->addButton(m_wholeProjectButton); diff --git a/src/plugins/todo/todooutputtreeview.cpp b/src/plugins/todo/todooutputtreeview.cpp index 5709fdc8a7..6c211f4613 100644 --- a/src/plugins/todo/todooutputtreeview.cpp +++ b/src/plugins/todo/todooutputtreeview.cpp @@ -104,6 +104,18 @@ void TodoOutputTreeView::resizeEvent(QResizeEvent *event) setColumnWidth(Constants::OUTPUT_COLUMN_FILE, widthFile); } +void TodoOutputTreeView::keyPressEvent(QKeyEvent *e) +{ + if (!e->modifiers() + && (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) + && currentIndex().isValid()) { + emit clicked(currentIndex()); + e->accept(); + return; + } + QTreeView::keyPressEvent(e); +} + void TodoOutputTreeView::todoColumnResized(int column, int oldSize, int newSize) { Q_UNUSED(oldSize); diff --git a/src/plugins/todo/todooutputtreeview.h b/src/plugins/todo/todooutputtreeview.h index 66ad9fbc13..123cd967ad 100644 --- a/src/plugins/todo/todooutputtreeview.h +++ b/src/plugins/todo/todooutputtreeview.h @@ -43,6 +43,7 @@ public: ~TodoOutputTreeView(); void resizeEvent(QResizeEvent *event); + void keyPressEvent(QKeyEvent *e); private slots: void todoColumnResized(int column, int oldSize, int newSize); diff --git a/src/plugins/valgrind/valgrindplugin.cpp b/src/plugins/valgrind/valgrindplugin.cpp index f7392831e3..3cef9593ea 100644 --- a/src/plugins/valgrind/valgrindplugin.cpp +++ b/src/plugins/valgrind/valgrindplugin.cpp @@ -85,7 +85,7 @@ public: class ValgrindAction : public AnalyzerAction { public: - ValgrindAction() {} + explicit ValgrindAction(QObject *parent = 0) : AnalyzerAction(parent) { } }; @@ -114,7 +114,7 @@ bool ValgrindPlugin::initialize(const QStringList &, QString *) "\"memcheck\" tool to find memory leaks."); if (!Utils::HostOsInfo::isWindowsHost()) { - action = new ValgrindAction; + action = new ValgrindAction(this); action->setId("Memcheck.Local"); action->setTool(m_memcheckTool); action->setText(tr("Valgrind Memory Analyzer")); @@ -124,7 +124,7 @@ bool ValgrindPlugin::initialize(const QStringList &, QString *) action->setEnabled(false); AnalyzerManager::addAction(action); - action = new ValgrindAction; + action = new ValgrindAction(this); action->setId("Callgrind.Local"); action->setTool(m_callgrindTool); action->setText(tr("Valgrind Function Profiler")); @@ -135,7 +135,7 @@ bool ValgrindPlugin::initialize(const QStringList &, QString *) AnalyzerManager::addAction(action); } - action = new ValgrindAction; + action = new ValgrindAction(this); action->setId("Memcheck.Remote"); action->setTool(m_memcheckTool); action->setText(tr("Valgrind Memory Analyzer (Remote)")); @@ -144,7 +144,7 @@ bool ValgrindPlugin::initialize(const QStringList &, QString *) action->setStartMode(StartRemote); AnalyzerManager::addAction(action); - action = new ValgrindAction; + action = new ValgrindAction(this); action->setId("Callgrind.Remote"); action->setTool(m_callgrindTool); action->setText(tr("Valgrind Function Profiler (Remote)")); diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index 395de4e238..fc73d89c67 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -732,7 +732,7 @@ QString VcsBasePlugin::findRepositoryForDirectory(const QString &dirS, qDebug() << "<VcsBasePlugin::findRepositoryForDirectory> " << absDirPath; return absDirPath; } - } while (directory.cdUp()); + } while (!directory.isRoot() && directory.cdUp()); if (debugRepositorySearch) qDebug() << "<VcsBasePlugin::findRepositoryForDirectory bailing out at " << directory.absolutePath(); return QString(); diff --git a/src/qtcreatorplugin.pri b/src/qtcreatorplugin.pri index c243fa1180..0f482d0a3d 100644 --- a/src/qtcreatorplugin.pri +++ b/src/qtcreatorplugin.pri @@ -112,12 +112,8 @@ greaterThan(QT_MAJOR_VERSION, 4) { } macx { - !isEmpty(TIGER_COMPAT_MODE) { - QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../PlugIns/$${PROVIDER}/ - } else { - QMAKE_LFLAGS_SONAME = -Wl,-install_name,@rpath/PlugIns/$${PROVIDER}/ - QMAKE_LFLAGS += -Wl,-rpath,@loader_path/../../,-rpath,@executable_path/../ - } + QMAKE_LFLAGS_SONAME = -Wl,-install_name,@rpath/PlugIns/$${PROVIDER}/ + QMAKE_LFLAGS += -Wl,-rpath,@loader_path/../../,-rpath,@executable_path/../ } else:linux-* { #do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR QMAKE_RPATHDIR += \$\$ORIGIN diff --git a/src/rpath.pri b/src/rpath.pri index c352a823b3..de56f11ae5 100644 --- a/src/rpath.pri +++ b/src/rpath.pri @@ -1,10 +1,6 @@ macx { - !isEmpty(TIGER_COMPAT_MODE) { - QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../PlugIns/ - } else { - QMAKE_LFLAGS_SONAME = -Wl,-install_name,@rpath/PlugIns/ - QMAKE_LFLAGS += -Wl,-rpath,@loader_path/../,-rpath,@executable_path/../ - } + QMAKE_LFLAGS_SONAME = -Wl,-install_name,@rpath/PlugIns/ + QMAKE_LFLAGS += -Wl,-rpath,@loader_path/../,-rpath,@executable_path/../ } else:linux-* { #do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR # this expands to $ORIGIN (after qmake and make), it does NOT read a qmake var diff --git a/src/shared/qbs b/src/shared/qbs -Subproject 89a1e502e0d33ce775515dd55ebb40ddbc4143b +Subproject 3b6b1b7fbc50bca101ad89a8acd80774bc668dd diff --git a/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp b/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp index 7afbe50dbb..5f31c27d7e 100644 --- a/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp +++ b/src/tools/cplusplus-mkvisitor/cplusplus-mkvisitor.cpp @@ -27,19 +27,19 @@ ** ****************************************************************************/ -#include <AST.h> -#include <ASTVisitor.h> -#include <ASTPatternBuilder.h> -#include <ASTMatcher.h> -#include <Control.h> -#include <Scope.h> -#include <Bind.h> -#include <TranslationUnit.h> -#include <Literals.h> -#include <Symbols.h> -#include <Names.h> -#include <CoreTypes.h> -#include <SymbolVisitor.h> +#include <cplusplus/AST.h> +#include <cplusplus/ASTVisitor.h> +#include <cplusplus/ASTPatternBuilder.h> +#include <cplusplus/ASTMatcher.h> +#include <cplusplus/Control.h> +#include <cplusplus/Scope.h> +#include <cplusplus/Bind.h> +#include <cplusplus/TranslationUnit.h> +#include <cplusplus/Literals.h> +#include <cplusplus/Symbols.h> +#include <cplusplus/Names.h> +#include <cplusplus/CoreTypes.h> +#include <cplusplus/SymbolVisitor.h> #include <cplusplus/CppDocument.h> #include <cplusplus/Overview.h> #include <cplusplus/LookupContext.h> diff --git a/src/tools/iostool/iosdevicemanager.cpp b/src/tools/iostool/iosdevicemanager.cpp index 2e3db289d2..88815ff8fd 100644 --- a/src/tools/iostool/iosdevicemanager.cpp +++ b/src/tools/iostool/iosdevicemanager.cpp @@ -125,7 +125,7 @@ typedef am_res_t (MDEV_API *AMDeviceInstallApplicationPtr)(ServiceSocket, CFStri typedef am_res_t (MDEV_API *AMDeviceUninstallApplicationPtr)(ServiceSocket, CFStringRef, CFDictionaryRef, AMDeviceInstallApplicationCallback, void*); -typedef am_res_t (MDEV_API *AMDeviceLookupApplicationsPtr)(AMDeviceRef, unsigned int, CFDictionaryRef *); +typedef am_res_t (MDEV_API *AMDeviceLookupApplicationsPtr)(AMDeviceRef, CFDictionaryRef, CFDictionaryRef *); } // extern C QString CFStringRef2QString(CFStringRef s) @@ -204,7 +204,7 @@ public : am_res_t deviceUninstallApplication(int, CFStringRef, CFDictionaryRef, AMDeviceInstallApplicationCallback, void*); - am_res_t deviceLookupApplications(AMDeviceRef, unsigned int, CFDictionaryRef *); + am_res_t deviceLookupApplications(AMDeviceRef, CFDictionaryRef, CFDictionaryRef *); void addError(const QString &msg); void addError(const char *msg); @@ -1063,6 +1063,8 @@ bool AppOpSession::installApp() } stopService(fd); } + if (!failure) + sleep(5); // after installation the device needs a bit of quiet.... if (debugAll) qDebug() << "AMDeviceInstallApplication finished request with " << failure; IosDeviceManagerPrivate::instance()->didTransferApp(bundlePath, deviceId, @@ -1091,6 +1093,7 @@ void AppOpSession::deviceCallbackReturned() bool AppOpSession::runApp() { bool failure = (device == 0); + QString exe = appPathOnDevice(); ServiceSocket gdbFd = -1; if (!failure && !startService(QLatin1String("com.apple.debugserver"), gdbFd)) gdbFd = -1; @@ -1103,7 +1106,6 @@ bool AppOpSession::runApp() if (!failure) failure = !sendGdbCommand(gdbFd, "QEnvironmentHexEncoded:"); // send the environment with a series of these commands... if (!failure) failure = !sendGdbCommand(gdbFd, "QSetDisableASLR:1"); // avoid address randomization to debug if (!failure) failure = !expectGdbOkReply(gdbFd); - QString exe = appPathOnDevice(); QStringList args = extraArgs; QByteArray runCommand("A"); args.insert(0, exe); @@ -1151,10 +1153,21 @@ QString AppOpSession::appPathOnDevice() if (!connectDevice()) return QString(); CFDictionaryRef apps; - if (int err = lib()->deviceLookupApplications(device, 0, &apps)) { + CFDictionaryRef options; + const void *attributes[3] = { (const void*)(CFSTR("CFBundleIdentifier")), + (const void*)(CFSTR("Path")), (const void*)(CFSTR("CFBundleExecutable")) }; + CFArrayRef lookupKeys = CFArrayCreate(kCFAllocatorDefault, (const void**)(&attributes[0]), 3, + &kCFTypeArrayCallBacks); + CFStringRef attrKey = CFSTR("ReturnAttributes"); + options = CFDictionaryCreate(kCFAllocatorDefault, (const void**)(&attrKey), + (const void**)(&lookupKeys), 1, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFRelease(lookupKeys); + if (int err = lib()->deviceLookupApplications(device, options, &apps)) { addError(QString::fromLatin1("app lookup failed, AMDeviceLookupApplications returned %1") .arg(err)); } + CFRelease(options); if (debugAll) CFShow(apps); if (apps && CFGetTypeID(apps) == CFDictionaryGetTypeID()) { @@ -1509,11 +1522,11 @@ am_res_t MobileDeviceLib::deviceUninstallApplication(int serviceFd, CFStringRef return -1; } -am_res_t MobileDeviceLib::deviceLookupApplications(AMDeviceRef device, unsigned int i, +am_res_t MobileDeviceLib::deviceLookupApplications(AMDeviceRef device, CFDictionaryRef options, CFDictionaryRef *res) { if (m_AMDeviceLookupApplications) - return m_AMDeviceLookupApplications(device, i, res); + return m_AMDeviceLookupApplications(device, options, res); return -1; } diff --git a/src/tools/iostool/main.cpp b/src/tools/iostool/main.cpp index 36cc9dba77..323e31c79a 100644 --- a/src/tools/iostool/main.cpp +++ b/src/tools/iostool/main.cpp @@ -106,7 +106,7 @@ IosTool::IosTool(QObject *parent): ipv6(false), inAppOutput(false), splitAppOutput(true), - appOp(Ios::IosDeviceManager::Install), + appOp(Ios::IosDeviceManager::None), outFile(), out(&outFile), gdbFileDescriptor(-1), @@ -281,7 +281,7 @@ void IosTool::didTransferApp(const QString &bundlePath, const QString &deviceId, //out.writeCharacters(QString()); // trigger a complete closing of the empty element outFile.flush(); if (status != Ios::IosDeviceManager::Success || --opLeft == 0) - doExit(-1); + doExit((status == Ios::IosDeviceManager::Success) ? 0 : -1); } void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId, |