Merge remote-tracking branch 'origin/3.3'

Change-Id: I0ab4982e229d475b8e3575414b4bebbfea07498d
This commit is contained in:
Eike Ziller
2014-11-12 12:55:00 +01:00
217 changed files with 2087 additions and 1620 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -457,7 +457,7 @@
\li To continue running the program, press \key{F5}. \li To continue running the program, press \key{F5}.
\li To run to the line containing the cursor, press \ke{yCtrl+F10} \li To run to the line containing the cursor, press \key{Ctrl+F10}
(\key{Shift+F8} on OS X). (\key{Shift+F8} on OS X).
\li To run to the selected function when you are stepping into a nested \li To run to the selected function when you are stepping into a nested

View File

@@ -94,11 +94,6 @@
You can change the configuration of preconfigured tools and configure You can change the configuration of preconfigured tools and configure
additional tools in \QC \gui Options. additional tools in \QC \gui Options.
You can use \QC variables in the fields that you can select from
lists of available \QC variables (1).
\image qtcreator-external-tools.png "External Tools options"
To configure external tools: To configure external tools:
\list 1 \list 1

View File

@@ -612,7 +612,7 @@
\li Alt+Z, Alt+C \li Alt+Z, Alt+C
\li Alt+C, Alt+C \li Alt+C, Alt+C
\li Alt+G, Alt+C \li Alt+G, Alt+C
\li Alt+H, Alt+C \li Alt+G, Alt+C
\li Alt+P, Alt+S \li Alt+P, Alt+S
\li Alt+S, Alt+C \li Alt+S, Alt+C
\row \row
@@ -620,7 +620,7 @@
\li Alt+Z, Alt+D \li Alt+Z, Alt+D
\li Alt+C, Alt+D \li Alt+C, Alt+D
\li Alt+G, Alt+D \li Alt+G, Alt+D
\li Alt+H, Alt+D \li Alt+G, Alt+D
\li \li
\li Alt+S, Alt+D \li Alt+S, Alt+D
\row \row
@@ -644,7 +644,7 @@
\li Alt+Z, Alt+L \li Alt+Z, Alt+L
\li \li
\li Alt+G, Alt+L \li Alt+G, Alt+L
\li Alt+H, Alt+L \li Alt+G, Alt+L
\li Alt+P, Alt+F \li Alt+P, Alt+F
\li \li
\row \row
@@ -660,7 +660,7 @@
\li Alt+Z, Alt+S \li Alt+Z, Alt+S
\li \li
\li \li
\li Alt+H, Alt+S \li Alt+G, Alt+S
\li \li
\li \li
\row \row

View File

@@ -96,17 +96,10 @@
You can use \QC variables in arguments, executable paths, and working You can use \QC variables in arguments, executable paths, and working
directories. The variables take care of quoting their expansions, so you do directories. The variables take care of quoting their expansions, so you do
not need to put them in quotes. not need to put them in quotes. Select the
\inlineimage qtcreator-variables-button.png
The following \QC variables are available: (\gui {Variables}) button in a field to select from a list of variables that
are available in a particular context.
\list
\li %{buildDir}
\li %{sourceDir}
\endlist
\section1 Build Steps \section1 Build Steps

View File

@@ -31,7 +31,7 @@
\title Qt Quick UI Forms \title Qt Quick UI Forms
You can use \QC wizards to create UI forms tha have the filename extension You can use \QC wizards to create UI forms that have the filename extension
\e .ui.qml. The UI forms contain a purely declarative subset of the QML \e .ui.qml. The UI forms contain a purely declarative subset of the QML
language. It is recommended that you edit the forms in the \gui Design mode. language. It is recommended that you edit the forms in the \gui Design mode.
\QC enforces the use of the supported QML features by displaying error \QC enforces the use of the supported QML features by displaying error

View File

@@ -1,6 +1,5 @@
import qbs import qbs
import qbs.FileInfo import qbs.FileInfo
import QtcProduct
QtcProduct { QtcProduct {
type: "application" type: "application"

View File

@@ -1,6 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcFunctions import QtcFunctions
import QtcProduct
QtcProduct { QtcProduct {
type: "dynamiclibrary" type: "dynamiclibrary"

View File

@@ -1,7 +1,6 @@
import qbs 1.0 import qbs 1.0
import qbs.FileInfo import qbs.FileInfo
import QtcFunctions import QtcFunctions
import QtcProduct
QtcProduct { QtcProduct {
type: ["dynamiclibrary", "pluginSpec"] type: ["dynamiclibrary", "pluginSpec"]

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcProduct
QtcProduct { QtcProduct {
type: "application" // no Mac app bundle type: "application" // no Mac app bundle

View File

@@ -1582,14 +1582,20 @@ def qdump__QRegion(d, value):
ns = d.qtNamespace() ns = d.qtNamespace()
rectType = d.lookupType(ns + "QRect") rectType = d.lookupType(ns + "QRect")
d.putIntItem("numRects", n) d.putIntItem("numRects", n)
d.putSubItem("extents", d.createValue(pp + 2 * v, rectType)) if d.qtVersion() >= 0x050400:
d.putSubItem("innerRect", d.createValue(pp + 2 * v + rectType.sizeof, rectType)) # Changed in ee324e4ed
d.putIntItem("innerArea", d.extractInt(pp + 2 * v + 2 * rectType.sizeof)) d.putSubItem("extents", d.createValue(pp + 8 + v, rectType))
d.putSubItem("innerRect", d.createValue(pp + 8 + v + rectType.sizeof, rectType))
d.putIntItem("innerArea", d.extractInt(pp + 4))
else:
d.putSubItem("extents", d.createValue(pp + 2 * v, rectType))
d.putSubItem("innerRect", d.createValue(pp + 2 * v + rectType.sizeof, rectType))
d.putIntItem("innerArea", d.extractInt(pp + 2 * v + 2 * rectType.sizeof))
# FIXME # FIXME
try: try:
# Can fail if QVector<QRect> debuginfo is missing. # Can fail if QVector<QRect> debuginfo is missing.
vectType = d.lookupType("%sQVector<%sQRect>" % (ns, ns)) vectType = d.lookupType("%sQVector<%sQRect>" % (ns, ns))
d.putSubItem("rects", d.createValue(pp + v, vectType)) d.putSubItem("rects", d.createValue(pp + 8, vectType))
except: except:
with SubItem(d, "rects"): with SubItem(d, "rects"):
d.putItemCount(n) d.putItemCount(n)

View File

@@ -1,6 +1,6 @@
Label { Label {
text: "%1" text: "%1"
toolTip: "%1" tooltip: "%1"
} }
CheckBox { CheckBox {

View File

@@ -1,6 +1,6 @@
Label { Label {
text: "%1" text: "%1"
toolTip: "%1" tooltip: "%1"
} }
SpinBox { SpinBox {
maximumValue: 9999999 maximumValue: 9999999

View File

@@ -1,6 +1,6 @@
Label { Label {
text: "%1" text: "%1"
toolTip: "%1" tooltip: "%1"
} }
SpinBox { SpinBox {
maximumValue: 9999999 maximumValue: 9999999

View File

@@ -1,6 +1,6 @@
Label { Label {
text: "%1" text: "%1"
toolTip: "%1" tooltip: "%1"
} }
LineEdit { LineEdit {
backendValue: backendValues.%2 backendValue: backendValues.%2

View File

@@ -1,6 +1,6 @@
Label { Label {
text: "%1" text: "%1"
toolTip: "%1" tooltip: "%1"
} }
LineEdit { LineEdit {
backendValue: backendValues.%2 backendValue: backendValues.%2

View File

@@ -50,7 +50,7 @@ Column {
ComboBox { ComboBox {
model: ["LeftToRight", "TopToBottom"] model: ["LeftToRight", "TopToBottom"]
backendValue: backendValues.flow backendValue: backendValues.flow
scope: "Qt" scope: "Flow"
} }
ExpandingSpacer { ExpandingSpacer {

View File

@@ -85,7 +85,7 @@ Column {
model: ["LeftToRight", "TopToBottom"] model: ["LeftToRight", "TopToBottom"]
backendValue: backendValues.flow backendValue: backendValues.flow
Layout.fillWidth: true Layout.fillWidth: true
scope: "Qt" scope: "Grid"
} }
} }

View File

@@ -45,6 +45,11 @@
"source": "file.pro", "source": "file.pro",
"target": "%{ProFileName}", "target": "%{ProFileName}",
"openAsProject": true "openAsProject": true
},
{
"source": "../git.ignore",
"target": "%{ProjectDirectory}/.gitignore",
"condition": "%{JS: ('%{VersionControl}%{IsSubproject}' === 'G.Git') ? 'yes' : ''}"
} }
] ]
} }

View File

@@ -0,0 +1,72 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe

View File

@@ -73,8 +73,8 @@ ProgressBarColorFinished=ff5aaa3c
ProgressBarColorNormal=hoverBackground ProgressBarColorNormal=hoverBackground
ProgressBarTitleColor=text ProgressBarTitleColor=text
QtOutputFormatter_LinkTextColor=ff0000ff QtOutputFormatter_LinkTextColor=ff0000ff
SearchResultWidgetBackgroundColor=shadowBackground InfoBarBackground=shadowBackground
SearchResultWidgetTextColor=text InfoBarText=text
TextColorDisabled=textDisabled TextColorDisabled=textDisabled
TextColorHighlight=ffff0000 TextColorHighlight=ffff0000
TextColorNormal=text TextColorNormal=text
@@ -84,7 +84,8 @@ ToolBarBackgroundColor=shadowBackground
TreeViewArrowColorNormal=hoverBackground TreeViewArrowColorNormal=hoverBackground
TreeViewArrowColorSelected=text TreeViewArrowColorSelected=text
Welcome_BackgroundColorNormal=normalBackground Welcome_BackgroundColorNormal=normalBackground
Welcome_Button_BorderColor=0 Welcome_Button_BorderColorNormal=0
Welcome_Button_BorderColorPressed=0
Welcome_Button_TextColorNormal=ffe7e7e7 Welcome_Button_TextColorNormal=ffe7e7e7
Welcome_Button_TextColorPressed=ffffffff Welcome_Button_TextColorPressed=ffffffff
Welcome_Caption_TextColorNormal=ff4acb47 Welcome_Caption_TextColorNormal=ff4acb47

View File

@@ -67,8 +67,8 @@ ProgressBarColorFinished=ff5aaa3c
ProgressBarColorNormal=b4ffffff ProgressBarColorNormal=b4ffffff
ProgressBarTitleColor=ffffffff ProgressBarTitleColor=ffffffff
QtOutputFormatter_LinkTextColor=ff0000aa QtOutputFormatter_LinkTextColor=ff0000aa
SearchResultWidgetBackgroundColor=ffffffff InfoBarBackground=ffffffe1
SearchResultWidgetTextColor=ff000000 InfoBarText=ff000000
TextColorDisabled=ff000000 TextColorDisabled=ff000000
TextColorHighlight=ffa0a0a4 TextColorHighlight=ffa0a0a4
TextColorNormal=ff000000 TextColorNormal=ff000000
@@ -78,7 +78,8 @@ ToolBarBackgroundColor=ffff0000
TreeViewArrowColorNormal=ffff0000 TreeViewArrowColorNormal=ffff0000
TreeViewArrowColorSelected=ffff0000 TreeViewArrowColorSelected=ffff0000
Welcome_BackgroundColorNormal=ffffffff Welcome_BackgroundColorNormal=ffffffff
Welcome_Button_BorderColor=ff737373 Welcome_Button_BorderColorNormal=ff737373
Welcome_Button_BorderColorPressed=ff333333
Welcome_Button_TextColorNormal=ff000000 Welcome_Button_TextColorNormal=ff000000
Welcome_Button_TextColorPressed=ffc0c0c0 Welcome_Button_TextColorPressed=ffc0c0c0
Welcome_Caption_TextColorNormal=ff328930 Welcome_Caption_TextColorNormal=ff328930

View File

@@ -40,7 +40,7 @@ Controls.ScrollView {
Item { Item {
id: canvas id: canvas
implicitWidth: childrenRect.width + 200 implicitWidth: childrenRect.width
implicitHeight: childrenRect.height implicitHeight: childrenRect.height
Button { Button {
@@ -97,8 +97,6 @@ Controls.ScrollView {
anchors.top: recentProjectsTitle.bottom anchors.top: recentProjectsTitle.bottom
anchors.topMargin: 20 anchors.topMargin: 20
anchors.right: parent.right
anchors.rightMargin: 60
model: projectList model: projectList
} }

View File

@@ -86,7 +86,7 @@ Button {
color: (creatorTheme.WidgetStyle === 'StyleFlat') ? "#232323" : "#eeeeee" color: (creatorTheme.WidgetStyle === 'StyleFlat') ? "#232323" : "#eeeeee"
} }
} }
border.color: creatorTheme.Welcome_Button_BorderColor border.color: creatorTheme.Welcome_Button_BorderColorNormal
} }
Rectangle { Rectangle {
@@ -114,7 +114,7 @@ Button {
color: (creatorTheme.WidgetStyle === 'StyleFlat') ? "#151515" : "#424242" color: (creatorTheme.WidgetStyle === 'StyleFlat') ? "#151515" : "#424242"
} }
} }
border.color: creatorTheme.Welcome_Button_BorderColor border.color: creatorTheme.Welcome_Button_BorderColorPressed
} }
} }

View File

@@ -34,6 +34,7 @@ import QtQuick.Controls 1.0
Rectangle { Rectangle {
id: projectList id: projectList
height: column.height + 200 height: column.height + 200
width: column.width
color: creatorTheme.Welcome_BackgroundColorNormal color: creatorTheme.Welcome_BackgroundColorNormal
property alias model: repeater.model property alias model: repeater.model

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcLibrary
QtcLibrary { QtcLibrary {
name: "Aggregation" name: "Aggregation"

View File

@@ -493,8 +493,12 @@ void Document::setGlobalNamespace(Namespace *globalNamespace)
* *
* \param line the line number, starting with line 1 * \param line the line number, starting with line 1
* \param column the column number, starting with column 1 * \param column the column number, starting with column 1
* \param lineOpeningDeclaratorParenthesis optional output parameter, the line of the opening
parenthesis of the declarator starting with 1
* \param lineClosingBrace optional output parameter, the line of the closing brace starting with 1
*/ */
QString Document::functionAt(int line, int column) const QString Document::functionAt(int line, int column, int *lineOpeningDeclaratorParenthesis,
int *lineClosingBrace) const
{ {
if (line < 1 || column < 1) if (line < 1 || column < 1)
return QString(); return QString();
@@ -505,10 +509,8 @@ QString Document::functionAt(int line, int column) const
// Find the enclosing function scope (which might be several levels up, or we might be standing // Find the enclosing function scope (which might be several levels up, or we might be standing
// on it) // on it)
Scope *scope; Scope *scope = symbol->asScope();
if (symbol->isScope()) if (!scope)
scope = symbol->asScope();
else
scope = symbol->enclosingScope(); scope = symbol->enclosingScope();
while (scope && !scope->isFunction() ) while (scope && !scope->isFunction() )
@@ -517,22 +519,21 @@ QString Document::functionAt(int line, int column) const
if (!scope) if (!scope)
return QString(); return QString();
// We found the function scope, extract its name. // We found the function scope
const Overview o; if (lineOpeningDeclaratorParenthesis) {
QString rc = o.prettyName(scope->name()); unsigned line;
translationUnit()->getPosition(scope->startOffset(), &line);
// Prepend namespace "Foo::Foo::foo()" up to empty root namespace *lineOpeningDeclaratorParenthesis = static_cast<int>(line);
for (const Symbol *owner = scope->enclosingNamespace();
owner; owner = owner->enclosingNamespace()) {
const QString name = o.prettyName(owner->name());
if (name.isEmpty()) {
break;
} else {
rc.prepend(QLatin1String("::"));
rc.prepend(name);
}
} }
return rc;
if (lineClosingBrace) {
unsigned line;
translationUnit()->getPosition(scope->endOffset(), &line);
*lineClosingBrace = static_cast<int>(line);
}
const QList<const Name *> fullyQualifiedName = LookupContext::fullyQualifiedName(scope);
return Overview().prettyName(fullyQualifiedName);
} }
Scope *Document::scopeAt(unsigned line, unsigned column) Scope *Document::scopeAt(unsigned line, unsigned column)

View File

@@ -101,7 +101,8 @@ public:
QList<Macro> definedMacros() const QList<Macro> definedMacros() const
{ return _definedMacros; } { return _definedMacros; }
QString functionAt(int line, int column) const; QString functionAt(int line, int column, int *lineOpeningDeclaratorParenthesis = 0,
int *lineClosingBrace = 0) const;
Symbol *lastVisibleSymbolAt(unsigned line, unsigned column = 0) const; Symbol *lastVisibleSymbolAt(unsigned line, unsigned column = 0) const;
Scope *scopeAt(unsigned line, unsigned column = 0); Scope *scopeAt(unsigned line, unsigned column = 0);

View File

@@ -200,6 +200,36 @@ private:
ClassOrNamespace *_binding; ClassOrNamespace *_binding;
}; };
static int evaluateFunctionArgument(const FullySpecifiedType &actualTy,
const FullySpecifiedType &formalTy)
{
int score = 0;
if (actualTy.type()->match(formalTy.type())) {
++score;
if (actualTy.isConst() == formalTy.isConst())
++score;
} else if (actualTy.simplified().type()->match(formalTy.simplified().type())) {
++score;
if (actualTy.simplified().isConst() == formalTy.simplified().isConst())
++score;
} else {
PointerType *actualAsPointer = actualTy.type()->asPointerType();
PointerType *formalAsPointer = formalTy.type()->asPointerType();
if (actualAsPointer && formalAsPointer) {
FullySpecifiedType actualElementType = actualAsPointer->elementType();
FullySpecifiedType formalElementType = formalAsPointer->elementType();
if (actualElementType.type()->match(formalElementType.type())) {
++score;
if (actualElementType.isConst() == formalElementType.isConst())
++score;
}
}
}
return score;
}
} // end of anonymous namespace } // end of anonymous namespace
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@@ -771,15 +801,6 @@ bool ResolveExpression::maybeValidPrototype(Function *funTy, unsigned actualArgu
return funTy->maybeValidPrototype(actualArgumentCount); return funTy->maybeValidPrototype(actualArgumentCount);
} }
bool ResolveExpression::implicitConversion(const FullySpecifiedType &sourceTy, const FullySpecifiedType &targetTy) const
{
if (sourceTy.match(targetTy))
return true;
else if (sourceTy.simplified().match(targetTy.simplified()))
return true;
return false;
}
bool ResolveExpression::visit(CallAST *ast) bool ResolveExpression::visit(CallAST *ast)
{ {
const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope); const QList<LookupItem> baseResults = resolve(ast->base_expression, _scope);
@@ -820,11 +841,13 @@ bool ResolveExpression::visit(CallAST *ast)
continue; continue;
actualTy = actual.first().type(); actualTy = actual.first().type();
} else } else {
actualTy = formalTy; actualTy = formalTy;
score += 2;
continue;
}
if (implicitConversion(actualTy, formalTy)) score += evaluateFunctionArgument(actualTy, formalTy);
++score;
} }
sortedResults.insert(LookupMap::value_type(-score, base)); sortedResults.insert(LookupMap::value_type(-score, base));

View File

@@ -77,7 +77,6 @@ protected:
void addResults(const QList<LookupItem> &items); void addResults(const QList<LookupItem> &items);
static bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount); static bool maybeValidPrototype(Function *funTy, unsigned actualArgumentCount);
bool implicitConversion(const FullySpecifiedType &sourceTy, const FullySpecifiedType &targetTy) const;
using ASTVisitor::visit; using ASTVisitor::visit;

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcLibrary
QtcLibrary { QtcLibrary {
name: "CPlusPlus" name: "CPlusPlus"

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcLibrary
QtcLibrary { QtcLibrary {
name: "ExtensionSystem" name: "ExtensionSystem"

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcLibrary
QtcLibrary { QtcLibrary {
name: "GLSL" name: "GLSL"

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcLibrary
QtcLibrary { QtcLibrary {
name: "LanguageUtils" name: "LanguageUtils"

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcLibrary
QtcLibrary { QtcLibrary {
name: "QmlDebug" name: "QmlDebug"

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcLibrary
QtcLibrary { QtcLibrary {
name: "QmlEditorWidgets" name: "QmlEditorWidgets"

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcLibrary
QtcLibrary { QtcLibrary {
name: "QmlJS" name: "QmlJS"

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcLibrary
QtcLibrary { QtcLibrary {
name: "QtcSsh" name: "QtcSsh"

View File

@@ -200,95 +200,137 @@ struct RemoveCvAndReference
typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type; typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type;
}; };
template<typename F, typename T> // abstraction to treat Container<T> and QStringList similarly
struct ResultOfFunctionWithoutCvAndReference template<typename T>
struct ContainerType
{ {
typedef typename RemoveCvAndReference<decltype(declval<F>()(declval<T>()))>::type type;
}; };
// actual implementation of transform // specialization for qt container T_Container<T_Type>
template<template<typename> class C, // result container type template<template<typename> class T_Container, typename T_Type>
template<typename> class SC, // input container type struct ContainerType<T_Container<T_Type>> {
typename T, // element type of input container typedef T_Type ElementType;
typename F> // function type
Q_REQUIRED_RESULT template<class NewElementType>
auto transform_impl(const SC<T> &container, F function) struct WithElementType
-> C<typename ResultOfFunctionWithoutCvAndReference<F, T>::type> {
typedef T_Container<NewElementType> type;
};
};
// specialization for QStringList
template<>
struct ContainerType<QStringList>
{ {
C<typename ResultOfFunctionWithoutCvAndReference<F, T>::type> result; typedef QString ElementType;
result.reserve(container.size());
std::transform(container.begin(), container.end(), template<class NewElementType>
inserter(result), struct WithElementType
function); {
return result; typedef QList<NewElementType> type;
} };
};
} }
// transform taking a member function pointer // actual implementation of transform
template<template<typename> class C, template<typename C, // result container type
typename T, typename SC> // input container type
struct TransformImpl {
template <typename F>
Q_REQUIRED_RESULT
static C call(const SC &container, F function)
{
C result;
result.reserve(container.size());
std::transform(container.begin(), container.end(),
inserter(result),
function);
return result;
}
template <typename R, typename S>
Q_REQUIRED_RESULT
static C call(const SC &container, R (S::*p)() const)
{
return call(container, std::mem_fn(p));
}
};
// same container type for input and output, e.g. transforming a QList<QString> into QList<int>
// or QStringList -> QList<>
template<typename C, // container
typename F>
Q_REQUIRED_RESULT
auto transform(const C &container, F function)
-> typename ContainerType<C>::template WithElementType< // the type C<stripped return type of F>
typename RemoveCvAndReference< // the return type of F stripped
decltype(declval<F>()(declval<typename ContainerType<C>::ElementType>())) // the return type of F
>::type
>::type
{
return TransformImpl<
typename ContainerType<C>::template WithElementType< // the type C<stripped return type>
typename RemoveCvAndReference< // the return type stripped
decltype(declval<F>()(declval<typename ContainerType<C>::ElementType>())) // the return type of F
>::type
>::type,
C
>::call(container, function);
}
// same container type for member function pointer
template<typename C,
typename R, typename R,
typename S> typename S>
Q_REQUIRED_RESULT Q_REQUIRED_RESULT
auto transform(const C<T> &container, R (S::*p)() const) auto transform(const C &container, R (S::*p)() const)
-> C<typename RemoveCvAndReference<R>::type> ->typename ContainerType<C>::template WithElementType<typename RemoveCvAndReference<R>::type>::type
{ {
C<typename RemoveCvAndReference<R>::type> result; return TransformImpl<
result.reserve(container.size()); typename ContainerType<C>::template WithElementType< // the type C<stripped R>
std::transform(container.begin(), container.end(), typename RemoveCvAndReference<R>::type // stripped R
std::back_inserter(result), >::type,
std::mem_fn(p)); C
return result; >::call(container, p);
}
// same container type for input and output, e.g. transforming a QList<QString> into QList<int>
template<template<typename> class C, // container
typename T, // element type
typename F> // function type
Q_REQUIRED_RESULT
auto transform(const C<T> &container, F function)
-> C<typename RemoveCvAndReference<decltype(declval<F>()(declval<T>()))>::type>
{
return transform_impl<QList>(container, function);
} }
// different container types for input and output, e.g. transforming a QList into a QSet // different container types for input and output, e.g. transforming a QList into a QSet
template<template<typename> class C, // result container type template<template<typename> class C, // result container type
template<typename> class SC, // input container type typename SC, // input container type
typename T, // element type of input container
typename F> // function type typename F> // function type
Q_REQUIRED_RESULT Q_REQUIRED_RESULT
auto transform(const SC<T> &container, F function) auto transform(const SC &container, F function)
-> C<typename RemoveCvAndReference<decltype(declval<F>()(declval<T>()))>::type> -> C< // container C<stripped return type of F>
typename RemoveCvAndReference< // stripped return type of F
decltype(declval<F>()(declval<typename ContainerType<SC>::ElementType>())) // return type of F
>::type>
{ {
return transform_impl(container, function); return TransformImpl<
C< // result container type
typename RemoveCvAndReference< // stripped
decltype(declval<F>()(declval<typename ContainerType<SC>::ElementType>())) // return type of F
>::type>,
SC
>::call(container, function);
} }
// different container types for input and output, e.g. transforming a QList into a QSet
////////// // for member function pointers
// transform for QStringList, because that isn't a specialization but a separate type
// and g++ doesn't want to use the above templates for that
// clang and msvc do find the base class QList<QString>
//////////
// QStringList -> QList<>
template<typename F> // function type
Q_REQUIRED_RESULT
auto transform(const QStringList &container, F function)
-> QList<typename RemoveCvAndReference<decltype(declval<F>()(declval<QString>()))>::type>
{
return transform_impl<QList>(QList<QString>(container), function);
}
// QStringList -> any container type
template<template<typename> class C, // result container type template<template<typename> class C, // result container type
typename F> // function type typename SC, // input container type
typename R,
typename S>
Q_REQUIRED_RESULT Q_REQUIRED_RESULT
auto transform(const QStringList &container, F function) auto transform(const SC &container, R (S::*p)())
-> C<typename RemoveCvAndReference<decltype(declval<F>()(declval<QString>()))>::type> -> C<typename RemoveCvAndReference<R>::type>
{ {
return transform_impl<C>(QList<QString>(container), function); return TransformImpl<
C<typename RemoveCvAndReference<R>::type>,
SC
>::call(container, p);
} }
////////////////// //////////////////

View File

@@ -701,6 +701,8 @@ FileName FileName::relativeChildPath(const FileName &parent) const
/// Appends \a s, ensuring a / between the parts /// Appends \a s, ensuring a / between the parts
FileName &FileName::appendPath(const QString &s) FileName &FileName::appendPath(const QString &s)
{ {
if (s.isEmpty())
return *this;
if (!isEmpty() && !QString::endsWith(QLatin1Char('/'))) if (!isEmpty() && !QString::endsWith(QLatin1Char('/')))
appendString(QLatin1Char('/')); appendString(QLatin1Char('/'));
appendString(s); appendString(s);

View File

@@ -358,23 +358,27 @@ void MacroExpander::registerIntVariable(const QByteArray &variable,
* \sa registerVariable(), registerIntVariable(), registerPrefix() * \sa registerVariable(), registerIntVariable(), registerPrefix()
*/ */
void MacroExpander::registerFileVariables(const QByteArray &prefix, void MacroExpander::registerFileVariables(const QByteArray &prefix,
const QString &heading, const StringFunction &base) const QString &heading, const StringFunction &base, bool visibleInChooser)
{ {
registerVariable(prefix + kFilePathPostfix, registerVariable(prefix + kFilePathPostfix,
tr("%1: Full path including file name.").arg(heading), tr("%1: Full path including file name.").arg(heading),
[base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).filePath(); }); [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).filePath(); },
visibleInChooser);
registerVariable(prefix + kPathPostfix, registerVariable(prefix + kPathPostfix,
tr("%1: Full path excluding file name.").arg(heading), tr("%1: Full path excluding file name.").arg(heading),
[base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).path(); }); [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).path(); },
visibleInChooser);
registerVariable(prefix + kFileNamePostfix, registerVariable(prefix + kFileNamePostfix,
tr("%1: File name without path.").arg(heading), tr("%1: File name without path.").arg(heading),
[base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).fileName(); }); [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).fileName(); },
visibleInChooser);
registerVariable(prefix + kFileBaseNamePostfix, registerVariable(prefix + kFileBaseNamePostfix,
tr("%1: File base name without path and suffix.").arg(heading), tr("%1: File base name without path and suffix.").arg(heading),
[base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).baseName(); }); [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).baseName(); },
visibleInChooser);
} }
void MacroExpander::registerExtraResolver(const MacroExpander::ResolverFunction &value) void MacroExpander::registerExtraResolver(const MacroExpander::ResolverFunction &value)

View File

@@ -81,7 +81,8 @@ public:
const QString &description, const IntFunction &value); const QString &description, const IntFunction &value);
void registerFileVariables(const QByteArray &prefix, void registerFileVariables(const QByteArray &prefix,
const QString &heading, const StringFunction &value); const QString &heading, const StringFunction &value,
bool visibleInChooser = true);
void registerExtraResolver(const ResolverFunction &value); void registerExtraResolver(const ResolverFunction &value);

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcTool
QtcTool { QtcTool {
name: "qtcreator_ctrlc_stub" name: "qtcreator_ctrlc_stub"

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcTool
QtcTool { QtcTool {
name: "qtcreator_process_stub" name: "qtcreator_process_stub"

View File

@@ -174,6 +174,8 @@ void ProxyAction::updateToolTipWithKeySequence()
QString ProxyAction::stringWithAppendedShortcut(const QString &str, const QKeySequence &shortcut) QString ProxyAction::stringWithAppendedShortcut(const QString &str, const QKeySequence &shortcut)
{ {
QString s = str;
s.replace(QLatin1String("&&"), QLatin1String("&"));
return QString::fromLatin1("%1 <span style=\"color: gray; font-size: small\">%2</span>"). return QString::fromLatin1("%1 <span style=\"color: gray; font-size: small\">%2</span>").
arg(str, shortcut.toString(QKeySequence::NativeText)); arg(s, shortcut.toString(QKeySequence::NativeText));
} }

View File

@@ -111,8 +111,8 @@ public:
ProgressBarColorError, ProgressBarColorError,
ProgressBarColorFinished, ProgressBarColorFinished,
ProgressBarColorNormal, ProgressBarColorNormal,
SearchResultWidgetBackgroundColor, InfoBarBackground,
SearchResultWidgetTextColor, InfoBarText,
TextColorDisabled, TextColorDisabled,
TextColorHighlight, TextColorHighlight,
TextColorNormal, TextColorNormal,
@@ -136,7 +136,8 @@ public:
Welcome_TextColorHeading, // #535353 // Sessions, Recent Projects Welcome_TextColorHeading, // #535353 // Sessions, Recent Projects
Welcome_BackgroundColorNormal, // #ffffff Welcome_BackgroundColorNormal, // #ffffff
Welcome_DividerColor, // #737373 Welcome_DividerColor, // #737373
Welcome_Button_BorderColor, Welcome_Button_BorderColorNormal,
Welcome_Button_BorderColorPressed,
Welcome_Button_TextColorNormal, Welcome_Button_TextColorNormal,
Welcome_Button_TextColorPressed, Welcome_Button_TextColorPressed,
Welcome_Link_TextColorNormal, Welcome_Link_TextColorNormal,

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcLibrary
QtcLibrary { QtcLibrary {
name: "Utils" name: "Utils"

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "AnalyzerBase" name: "AnalyzerBase"

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "Android" name: "Android"

View File

@@ -131,6 +131,33 @@ namespace {
} }
return res; return res;
} }
static bool is32BitUserSpace()
{
// Do the exact same check as android's emulator is doing:
if (Utils::HostOsInfo::isLinuxHost()) {
if (QSysInfo::WordSize == 32 ) {
Utils::Environment env = Utils::Environment::systemEnvironment();
QString executable = env.searchInPath(QLatin1String("file")).toString();
QString shell = env.value(QLatin1String("SHELL"));
if (executable.isEmpty() || shell.isEmpty())
return true; // we can't detect, but creator is 32bit so assume 32bit
QProcess proc;
proc.setProcessChannelMode(QProcess::MergedChannels);
proc.start(executable, QStringList() << shell);
if (!proc.waitForFinished(2000)) {
proc.kill();
return true;
}
if (proc.readAll().contains("x86-64"))
return false;
return true;
}
}
return false;
}
} }
////////////////////////////////// //////////////////////////////////
@@ -660,9 +687,13 @@ bool AndroidConfig::startAVDAsync(const QString &avdName) const
avdProcess->connect(avdProcess, SIGNAL(finished(int)), avdProcess, SLOT(deleteLater())); avdProcess->connect(avdProcess, SIGNAL(finished(int)), avdProcess, SLOT(deleteLater()));
// start the emulator // start the emulator
avdProcess->start(emulatorToolPath().toString(), QStringList arguments;
QStringList() << QLatin1String("-partition-size") << QString::number(partitionSize()) if (AndroidConfigurations::force32bitEmulator())
<< QLatin1String("-avd") << avdName); arguments << QLatin1String("-force-32bit");
arguments << QLatin1String("-partition-size") << QString::number(partitionSize())
<< QLatin1String("-avd") << avdName;
avdProcess->start(emulatorToolPath().toString(), arguments);
if (!avdProcess->waitForStarted(-1)) { if (!avdProcess->waitForStarted(-1)) {
delete avdProcess; delete avdProcess;
return false; return false;
@@ -1166,6 +1197,11 @@ void AndroidConfigurations::updateAutomaticKitList()
} }
} }
bool AndroidConfigurations::force32bitEmulator()
{
return m_instance->m_force32bit;
}
/** /**
* Workaround for '????????????' serial numbers * Workaround for '????????????' serial numbers
* @return ("-d") for buggy devices, ("-s", <serial no>) for normal * @return ("-d") for buggy devices, ("-s", <serial no>) for normal
@@ -1203,6 +1239,8 @@ AndroidConfigurations::AndroidConfigurations(QObject *parent)
connect(ProjectExplorer::SessionManager::instance(), SIGNAL(projectRemoved(ProjectExplorer::Project*)), connect(ProjectExplorer::SessionManager::instance(), SIGNAL(projectRemoved(ProjectExplorer::Project*)),
this, SLOT(clearDefaultDevices(ProjectExplorer::Project*))); this, SLOT(clearDefaultDevices(ProjectExplorer::Project*)));
m_force32bit = is32BitUserSpace();
m_instance = this; m_instance = this;
} }

View File

@@ -215,6 +215,7 @@ public slots:
static void clearDefaultDevices(ProjectExplorer::Project *project); static void clearDefaultDevices(ProjectExplorer::Project *project);
static void updateToolChainList(); static void updateToolChainList();
static void updateAutomaticKitList(); static void updateAutomaticKitList();
static bool force32bitEmulator();
signals: signals:
void updated(); void updated();
@@ -228,6 +229,7 @@ private:
AndroidConfig m_config; AndroidConfig m_config;
QMap<ProjectExplorer::Project *, QMap<QString, QString> > m_defaultDeviceForAbi; QMap<ProjectExplorer::Project *, QMap<QString, QString> > m_defaultDeviceForAbi;
bool m_force32bit;
}; };
} // namespace Android } // namespace Android

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "AutotoolsProjectManager" name: "AutotoolsProjectManager"

View File

@@ -1,7 +1,5 @@
import qbs import qbs
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "BareMetal" name: "BareMetal"

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "Bazaar" name: "Bazaar"

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "Beautifier" name: "Beautifier"

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "BinEditor" name: "BinEditor"

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "Bookmarks" name: "Bookmarks"

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "ClassView" name: "ClassView"

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "ClearCase" name: "ClearCase"

View File

@@ -869,6 +869,20 @@ void CMakeCbpParser::sortFiles()
CMakeBuildTarget *last = 0; CMakeBuildTarget *last = 0;
Utils::FileName parentDirectory; Utils::FileName parentDirectory;
// find a good build target to fall back
int fallbackIndex = 0;
{
int bestIncludeCount = -1;
for (int i = 0; i < m_buildTargets.size(); ++i) {
const CMakeBuildTarget &target = m_buildTargets.at(i);
if (target.sourceDirectory == m_sourceDirectory
&& target.includeFiles.count() > bestIncludeCount) {
bestIncludeCount = target.includeFiles.count();
fallbackIndex = i;
}
}
}
foreach (const Utils::FileName &fileName, fileNames) { foreach (const Utils::FileName &fileName, fileNames) {
if (fileName.parentDir() == parentDirectory && last) { if (fileName.parentDir() == parentDirectory && last) {
// easy case, same parent directory as last file // easy case, same parent directory as last file
@@ -891,7 +905,7 @@ void CMakeCbpParser::sortFiles()
} }
if (bestIndex == -1 && !m_buildTargets.isEmpty()) if (bestIndex == -1 && !m_buildTargets.isEmpty())
bestIndex = 0; bestIndex = fallbackIndex;
if (bestIndex != -1) { if (bestIndex != -1) {
m_buildTargets[bestIndex].files.append(fileName.toString()); m_buildTargets[bestIndex].files.append(fileName.toString());

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "CMakeProjectManager" name: "CMakeProjectManager"

View File

@@ -307,6 +307,18 @@ Command *ActionContainerPrivate::addSeparator(const Context &context, Id group,
return cmd; return cmd;
} }
void ActionContainerPrivate::setEnabled(bool enabled)
{
foreach (const Group &group, m_groups) {
foreach (QObject *item, group.items) {
if (Command *command = qobject_cast<Command *>(item))
command->action()->setEnabled(enabled);
else if (ActionContainer *container = qobject_cast<ActionContainer *>(item))
container->setEnabled(enabled);
}
}
}
void ActionContainerPrivate::clear() void ActionContainerPrivate::clear()
{ {
QMutableListIterator<Group> it(m_groups); QMutableListIterator<Group> it(m_groups);

View File

@@ -72,6 +72,7 @@ public:
virtual void addMenu(ActionContainer *menu, Id group = Id()) = 0; virtual void addMenu(ActionContainer *menu, Id group = Id()) = 0;
virtual void addMenu(ActionContainer *before, ActionContainer *menu, Id group = Id()) = 0; virtual void addMenu(ActionContainer *before, ActionContainer *menu, Id group = Id()) = 0;
virtual Command *addSeparator(const Context &context, Id group = Id(), QAction **outSeparator = 0) = 0; virtual Command *addSeparator(const Context &context, Id group = Id(), QAction **outSeparator = 0) = 0;
virtual void setEnabled(bool enabled) = 0;
// This clears this menu and submenus from all actions and submenus. // This clears this menu and submenus from all actions and submenus.
// It does not destroy the submenus and commands, just removes them from their parents. // It does not destroy the submenus and commands, just removes them from their parents.

View File

@@ -64,6 +64,7 @@ public:
void addMenu(ActionContainer *menu, Id group = Id()); void addMenu(ActionContainer *menu, Id group = Id());
void addMenu(ActionContainer *before, ActionContainer *menu, Id group = Id()); void addMenu(ActionContainer *before, ActionContainer *menu, Id group = Id());
Command *addSeparator(const Context &context, Id group = Id(), QAction **outSeparator = 0); Command *addSeparator(const Context &context, Id group = Id(), QAction **outSeparator = 0);
void setEnabled(bool enabled);
virtual void clear(); virtual void clear();
Id id() const; Id id() const;

View File

@@ -313,6 +313,10 @@ void Action::addOverrideAction(QAction *action, const Core::Context &context, bo
{ {
if (Utils::HostOsInfo::isMacHost()) if (Utils::HostOsInfo::isMacHost())
action->setIconVisibleInMenu(false); action->setIconVisibleInMenu(false);
// disallow TextHeuristic menu role, because it doesn't work with translations,
// e.g. QTCREATORBUG-13101
if (action->menuRole() == QAction::TextHeuristicRole)
action->setMenuRole(QAction::NoRole);
if (isEmpty()) if (isEmpty())
m_action->initialize(action); m_action->initialize(action);
if (context.isEmpty()) { if (context.isEmpty()) {

View File

@@ -95,6 +95,7 @@ void CorePlugin::parseArguments(const QStringList &arguments)
QString themeName = QLatin1String("default"); QString themeName = QLatin1String("default");
QColor overrideColor; QColor overrideColor;
bool overrideTheme = false; bool overrideTheme = false;
bool presentationMode = false;
for (int i = 0; i < arguments.size(); ++i) { for (int i = 0; i < arguments.size(); ++i) {
if (arguments.at(i) == QLatin1String("-color")) { if (arguments.at(i) == QLatin1String("-color")) {
@@ -103,7 +104,7 @@ void CorePlugin::parseArguments(const QStringList &arguments)
i++; // skip the argument i++; // skip the argument
} }
if (arguments.at(i) == QLatin1String("-presentationMode")) if (arguments.at(i) == QLatin1String("-presentationMode"))
ActionManager::setPresentationModeEnabled(true); presentationMode = true;
if (arguments.at(i) == QLatin1String("-theme")) { if (arguments.at(i) == QLatin1String("-theme")) {
overrideTheme = true; overrideTheme = true;
themeName = arguments.at(i + 1); themeName = arguments.at(i + 1);
@@ -137,6 +138,7 @@ void CorePlugin::parseArguments(const QStringList &arguments)
// defer creation of these widgets until here, // defer creation of these widgets until here,
// because they need a valid theme set // because they need a valid theme set
m_mainWindow = new MainWindow; m_mainWindow = new MainWindow;
ActionManager::setPresentationModeEnabled(presentationMode);
m_findPlugin = new FindPlugin; m_findPlugin = new FindPlugin;
m_locator = new Locator; m_locator = new Locator;

View File

@@ -17,6 +17,7 @@ SOURCES += corejsextensions.cpp \
fancytabwidget.cpp \ fancytabwidget.cpp \
generalsettings.cpp \ generalsettings.cpp \
themesettings.cpp \ themesettings.cpp \
themesettingswidget.cpp \
id.cpp \ id.cpp \
icontext.cpp \ icontext.cpp \
jsexpander.cpp \ jsexpander.cpp \
@@ -121,6 +122,7 @@ HEADERS += corejsextensions.h \
fancytabwidget.h \ fancytabwidget.h \
generalsettings.h \ generalsettings.h \
themesettings.h \ themesettings.h \
themesettingswidget.h \
id.h \ id.h \
jsexpander.h \ jsexpander.h \
messagemanager.h \ messagemanager.h \

View File

@@ -1,6 +1,5 @@
import qbs 1.0 import qbs 1.0
import qbs.FileInfo import qbs.FileInfo
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "Core" name: "Core"
@@ -98,9 +97,8 @@ QtcPlugin {
"styleanimator.cpp", "styleanimator.h", "styleanimator.cpp", "styleanimator.h",
"tabpositionindicator.cpp", "tabpositionindicator.h", "tabpositionindicator.cpp", "tabpositionindicator.h",
"textdocument.cpp", "textdocument.h", "textdocument.cpp", "textdocument.h",
"themesettings.cpp", "themesettings.cpp", "themesettings.h", "themesettings.ui",
"themesettings.h", "themesettingswidget.cpp", "themesettingswidget.h",
"themesettings.ui",
"toolsettings.cpp", "toolsettings.h", "toolsettings.cpp", "toolsettings.h",
"variablechooser.cpp", "variablechooser.h", "variablechooser.cpp", "variablechooser.h",
"vcsmanager.cpp", "vcsmanager.h", "vcsmanager.cpp", "vcsmanager.h",

View File

@@ -200,7 +200,7 @@ DocumentManagerPrivate::DocumentManagerPrivate() :
m_linkWatcher(0), m_linkWatcher(0),
m_blockActivated(false), m_blockActivated(false),
m_lastVisitedDirectory(QDir::currentPath()), m_lastVisitedDirectory(QDir::currentPath()),
m_useProjectsDirectory(Utils::HostOsInfo::isMacHost()), // Creator is in bizarre places when launched via finder. m_useProjectsDirectory(true),
m_blockedIDocument(0) m_blockedIDocument(0)
{ {
} }

View File

@@ -225,12 +225,12 @@ FindToolBar::FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumen
m_ui.replaceButton->setDefaultAction(m_localReplaceAction); m_ui.replaceButton->setDefaultAction(m_localReplaceAction);
m_replaceNextAction = new QAction(tr("Replace && Find"), this); m_replaceNextAction = new QAction(tr("Replace && Find"), this);
m_replaceNextAction->setIconText(tr("Replace && Find")); // work around bug in Qt that kills ampersands in tool button
cmd = Core::ActionManager::registerAction(m_replaceNextAction, Constants::REPLACE_NEXT, globalcontext); cmd = Core::ActionManager::registerAction(m_replaceNextAction, Constants::REPLACE_NEXT, globalcontext);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+="))); cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+=")));
mfind->addAction(cmd, Constants::G_FIND_ACTIONS); mfind->addAction(cmd, Constants::G_FIND_ACTIONS);
connect(m_replaceNextAction, SIGNAL(triggered()), this, SLOT(invokeGlobalReplaceNext())); connect(m_replaceNextAction, SIGNAL(triggered()), this, SLOT(invokeGlobalReplaceNext()));
m_localReplaceNextAction = new QAction(m_replaceNextAction->text(), this); m_localReplaceNextAction = new QAction(m_replaceNextAction->text(), this);
m_localReplaceNextAction->setIconText(m_replaceNextAction->text()); // Workaround QTBUG-23396
cmd = ActionManager::registerAction(m_localReplaceNextAction, Constants::REPLACE_NEXT, findcontext); cmd = ActionManager::registerAction(m_localReplaceNextAction, Constants::REPLACE_NEXT, findcontext);
cmd->augmentActionWithShortcutToolTip(m_localReplaceNextAction); cmd->augmentActionWithShortcutToolTip(m_localReplaceNextAction);
connect(m_localReplaceNextAction, &QAction::triggered, this, &FindToolBar::invokeReplaceNext); connect(m_localReplaceNextAction, &QAction::triggered, this, &FindToolBar::invokeReplaceNext);

View File

@@ -96,8 +96,8 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
QFrame *topWidget = new QFrame; QFrame *topWidget = new QFrame;
QPalette pal; QPalette pal;
pal.setColor(QPalette::Window, creatorTheme()->color(Theme::SearchResultWidgetBackgroundColor)); pal.setColor(QPalette::Window, creatorTheme()->color(Theme::InfoBarBackground));
pal.setColor(QPalette::WindowText, creatorTheme()->color(Theme::SearchResultWidgetTextColor)); pal.setColor(QPalette::WindowText, creatorTheme()->color(Theme::InfoBarText));
topWidget->setPalette(pal); topWidget->setPalette(pal);
if (creatorTheme()->flag(Theme::DrawSearchResultWidgetFrame)) { if (creatorTheme()->flag(Theme::DrawSearchResultWidgetFrame)) {
topWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); topWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);

View File

@@ -73,6 +73,16 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="1" column="0">
<widget class="QLabel" name="themeLabel">
<property name="text">
<string>Theme:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Core::Internal::ThemeSettingsWidget" name="themeWidget" native="true"/>
</item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QLabel" name="languageLabel"> <widget class="QLabel" name="languageLabel">
<property name="text"> <property name="text">
@@ -334,6 +344,12 @@
<signal>browsingFinished()</signal> <signal>browsingFinished()</signal>
</slots> </slots>
</customwidget> </customwidget>
<customwidget>
<class>Core::Internal::ThemeSettingsWidget</class>
<extends>QWidget</extends>
<header location="global">coreplugin/themesettingswidget.h</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="core.qrc"/> <include location="core.qrc"/>

View File

@@ -33,6 +33,8 @@
#include "coreconstants.h" #include "coreconstants.h"
#include "icore.h" #include "icore.h"
#include <utils/theme/theme.h>
#include <QFrame> #include <QFrame>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
@@ -40,6 +42,8 @@
static const char C_SUPPRESSED_WARNINGS[] = "SuppressedWarnings"; static const char C_SUPPRESSED_WARNINGS[] = "SuppressedWarnings";
using namespace Utils;
namespace Core { namespace Core {
QSet<Id> InfoBar::globallySuppressed; QSet<Id> InfoBar::globallySuppressed;
@@ -202,8 +206,8 @@ void InfoBarDisplay::update()
QFrame *infoWidget = new QFrame; QFrame *infoWidget = new QFrame;
QPalette pal; QPalette pal;
pal.setColor(QPalette::Window, QColor(255, 255, 225)); pal.setColor(QPalette::Window, creatorTheme()->color(Theme::InfoBarBackground));
pal.setColor(QPalette::WindowText, Qt::black); pal.setColor(QPalette::WindowText, Theme::InfoBarText);
infoWidget->setPalette(pal); infoWidget->setPalette(pal);
infoWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); infoWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);

View File

@@ -132,7 +132,6 @@ MainWindow::MainWindow() :
m_rightPaneWidget(0), m_rightPaneWidget(0),
m_versionDialog(0), m_versionDialog(0),
m_generalSettings(new GeneralSettings), m_generalSettings(new GeneralSettings),
m_themeSettings(new ThemeSettings),
m_shortcutSettings(new ShortcutSettings), m_shortcutSettings(new ShortcutSettings),
m_toolSettings(new ToolSettings), m_toolSettings(new ToolSettings),
m_mimeTypeSettings(new MimeTypeSettings), m_mimeTypeSettings(new MimeTypeSettings),
@@ -256,7 +255,6 @@ MainWindow::~MainWindow()
ExtensionSystem::PluginManager::removeObject(m_shortcutSettings); ExtensionSystem::PluginManager::removeObject(m_shortcutSettings);
ExtensionSystem::PluginManager::removeObject(m_generalSettings); ExtensionSystem::PluginManager::removeObject(m_generalSettings);
ExtensionSystem::PluginManager::removeObject(m_themeSettings);
ExtensionSystem::PluginManager::removeObject(m_toolSettings); ExtensionSystem::PluginManager::removeObject(m_toolSettings);
ExtensionSystem::PluginManager::removeObject(m_mimeTypeSettings); ExtensionSystem::PluginManager::removeObject(m_mimeTypeSettings);
ExtensionSystem::PluginManager::removeObject(m_systemEditor); ExtensionSystem::PluginManager::removeObject(m_systemEditor);
@@ -268,8 +266,6 @@ MainWindow::~MainWindow()
m_shortcutSettings = 0; m_shortcutSettings = 0;
delete m_generalSettings; delete m_generalSettings;
m_generalSettings = 0; m_generalSettings = 0;
delete m_themeSettings;
m_themeSettings = 0;
delete m_toolSettings; delete m_toolSettings;
m_toolSettings = 0; m_toolSettings = 0;
delete m_mimeTypeSettings; delete m_mimeTypeSettings;
@@ -327,7 +323,6 @@ bool MainWindow::init(QString *errorMessage)
m_progressManager->init(); // needs the status bar manager m_progressManager->init(); // needs the status bar manager
ExtensionSystem::PluginManager::addObject(m_generalSettings); ExtensionSystem::PluginManager::addObject(m_generalSettings);
ExtensionSystem::PluginManager::addObject(m_themeSettings);
ExtensionSystem::PluginManager::addObject(m_shortcutSettings); ExtensionSystem::PluginManager::addObject(m_shortcutSettings);
ExtensionSystem::PluginManager::addObject(m_toolSettings); ExtensionSystem::PluginManager::addObject(m_toolSettings);
ExtensionSystem::PluginManager::addObject(m_mimeTypeSettings); ExtensionSystem::PluginManager::addObject(m_mimeTypeSettings);
@@ -567,9 +562,9 @@ void MainWindow::registerDefaultActions()
// Exit Action // Exit Action
icon = QIcon::fromTheme(QLatin1String("application-exit")); icon = QIcon::fromTheme(QLatin1String("application-exit"));
m_exitAction = new QAction(icon, tr("E&xit"), this); m_exitAction = new QAction(icon, tr("E&xit"), this);
m_exitAction->setMenuRole(QAction::QuitRole);
cmd = ActionManager::registerAction(m_exitAction, Constants::EXIT, globalContext); cmd = ActionManager::registerAction(m_exitAction, Constants::EXIT, globalContext);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Q"))); cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Q")));
cmd->action()->setMenuRole(QAction::QuitRole);
mfile->addAction(cmd, Constants::G_FILE_OTHER); mfile->addAction(cmd, Constants::G_FILE_OTHER);
connect(m_exitAction, SIGNAL(triggered()), this, SLOT(exit())); connect(m_exitAction, SIGNAL(triggered()), this, SLOT(exit()));
@@ -638,11 +633,9 @@ void MainWindow::registerDefaultActions()
mtools->addSeparator(globalContext, Constants::G_TOOLS_OPTIONS); mtools->addSeparator(globalContext, Constants::G_TOOLS_OPTIONS);
m_optionsAction = new QAction(tr("&Options..."), this); m_optionsAction = new QAction(tr("&Options..."), this);
m_optionsAction->setMenuRole(QAction::PreferencesRole);
cmd = ActionManager::registerAction(m_optionsAction, Constants::OPTIONS, globalContext); cmd = ActionManager::registerAction(m_optionsAction, Constants::OPTIONS, globalContext);
if (UseMacShortcuts) { cmd->setDefaultKeySequence(QKeySequence::Preferences);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+,")));
cmd->action()->setMenuRole(QAction::PreferencesRole);
}
mtools->addAction(cmd, Constants::G_TOOLS_OPTIONS); mtools->addAction(cmd, Constants::G_TOOLS_OPTIONS);
connect(m_optionsAction, SIGNAL(triggered()), this, SLOT(showOptionsDialog())); connect(m_optionsAction, SIGNAL(triggered()), this, SLOT(showOptionsDialog()));
@@ -665,7 +658,6 @@ void MainWindow::registerDefaultActions()
// Full Screen Action // Full Screen Action
QAction *toggleFullScreenAction = new QAction(tr("Full Screen"), this); QAction *toggleFullScreenAction = new QAction(tr("Full Screen"), this);
toggleFullScreenAction->setMenuRole(QAction::NoRole);
toggleFullScreenAction->setCheckable(!Utils::HostOsInfo::isMacHost()); toggleFullScreenAction->setCheckable(!Utils::HostOsInfo::isMacHost());
toggleFullScreenAction->setEnabled(false); // actual implementation in WindowSupport toggleFullScreenAction->setEnabled(false); // actual implementation in WindowSupport
cmd = ActionManager::registerAction(toggleFullScreenAction, Constants::TOGGLE_FULLSCREEN, globalContext); cmd = ActionManager::registerAction(toggleFullScreenAction, Constants::TOGGLE_FULLSCREEN, globalContext);
@@ -721,18 +713,16 @@ void MainWindow::registerDefaultActions()
tmpaction = new QAction(icon, tr("About &Qt Creator"), this); // it's convention not to add dots to the about menu tmpaction = new QAction(icon, tr("About &Qt Creator"), this); // it's convention not to add dots to the about menu
else else
tmpaction = new QAction(icon, tr("About &Qt Creator..."), this); tmpaction = new QAction(icon, tr("About &Qt Creator..."), this);
tmpaction->setMenuRole(QAction::AboutRole);
cmd = ActionManager::registerAction(tmpaction, Constants::ABOUT_QTCREATOR, globalContext); cmd = ActionManager::registerAction(tmpaction, Constants::ABOUT_QTCREATOR, globalContext);
if (Utils::HostOsInfo::isMacHost())
cmd->action()->setMenuRole(QAction::ApplicationSpecificRole);
mhelp->addAction(cmd, Constants::G_HELP_ABOUT); mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
tmpaction->setEnabled(true); tmpaction->setEnabled(true);
connect(tmpaction, SIGNAL(triggered()), this, SLOT(aboutQtCreator())); connect(tmpaction, SIGNAL(triggered()), this, SLOT(aboutQtCreator()));
//About Plugins Action //About Plugins Action
tmpaction = new QAction(tr("About &Plugins..."), this); tmpaction = new QAction(tr("About &Plugins..."), this);
tmpaction->setMenuRole(QAction::ApplicationSpecificRole);
cmd = ActionManager::registerAction(tmpaction, Constants::ABOUT_PLUGINS, globalContext); cmd = ActionManager::registerAction(tmpaction, Constants::ABOUT_PLUGINS, globalContext);
if (Utils::HostOsInfo::isMacHost())
cmd->action()->setMenuRole(QAction::ApplicationSpecificRole);
mhelp->addAction(cmd, Constants::G_HELP_ABOUT); mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
tmpaction->setEnabled(true); tmpaction->setEnabled(true);
connect(tmpaction, SIGNAL(triggered()), this, SLOT(aboutPlugins())); connect(tmpaction, SIGNAL(triggered()), this, SLOT(aboutPlugins()));

View File

@@ -72,7 +72,6 @@ namespace Internal {
class ActionManagerPrivate; class ActionManagerPrivate;
class FancyTabWidget; class FancyTabWidget;
class GeneralSettings; class GeneralSettings;
class ThemeSettings;
class ProgressManagerPrivate; class ProgressManagerPrivate;
class ShortcutSettings; class ShortcutSettings;
class ToolSettings; class ToolSettings;
@@ -192,7 +191,6 @@ private:
QMap<QWidget *, IContext *> m_contextWidgets; QMap<QWidget *, IContext *> m_contextWidgets;
GeneralSettings *m_generalSettings; GeneralSettings *m_generalSettings;
ThemeSettings *m_themeSettings;
ShortcutSettings *m_shortcutSettings; ShortcutSettings *m_shortcutSettings;
ToolSettings *m_toolSettings; ToolSettings *m_toolSettings;
MimeTypeSettings *m_mimeTypeSettings; MimeTypeSettings *m_mimeTypeSettings;

View File

@@ -45,7 +45,7 @@ ThemeColorsTableView::ThemeColorsTableView(QWidget *parent)
void ThemeColorsTableView::mousePressEvent(QMouseEvent *event) void ThemeColorsTableView::mousePressEvent(QMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton) { if ((editTriggers() & NoEditTriggers) && (event->button() == Qt::LeftButton)) {
QModelIndex index = indexAt(event->pos()); QModelIndex index = indexAt(event->pos());
if (model()->flags(index) & Qt::ItemIsEditable && index.column() == 1) { if (model()->flags(index) & Qt::ItemIsEditable && index.column() == 1) {
setCurrentIndex(index); setCurrentIndex(index);

View File

@@ -79,6 +79,8 @@ ThemeEditorWidget::~ThemeEditorWidget()
void ThemeEditorWidget::changeColor(const QModelIndex &index) void ThemeEditorWidget::changeColor(const QModelIndex &index)
{ {
if (!(m_ui->tableView->editTriggers() & QAbstractItemView::DoubleClicked))
return;
if (m_model->inSectionBody(index.row()) != ThemeSettingsTableModel::SectionColors) if (m_model->inSectionBody(index.row()) != ThemeSettingsTableModel::SectionColors)
return; return;
if (index.column() == 1) if (index.column() == 1)
@@ -114,7 +116,9 @@ void ThemeEditorWidget::changeColor(const QModelIndex &index)
void ThemeEditorWidget::setReadOnly(bool readOnly) void ThemeEditorWidget::setReadOnly(bool readOnly)
{ {
m_readOnly = readOnly; m_readOnly = readOnly;
m_ui->tableView->setEnabled(!readOnly); m_ui->tableView->setEditTriggers(
readOnly ? QAbstractItemView::NoEditTriggers
: QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
m_ui->filter->setEnabled(!readOnly); m_ui->filter->setEnabled(!readOnly);
} }

View File

@@ -29,436 +29,46 @@
****************************************************************************/ ****************************************************************************/
#include "themesettings.h" #include "themesettings.h"
#include "themesettingswidget.h"
#include "coreconstants.h" #include "coreconstants.h"
#include "icore.h"
#include "editormanager/editormanager_p.h"
#include "themeeditor/themesettingstablemodel.h"
#include <utils/qtcassert.h> #include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QInputDialog>
#include <QMessageBox>
#include <QSettings>
#include "ui_themesettings.h"
using namespace Utils;
namespace Core { namespace Core {
namespace Internal { namespace Internal {
const char themeNameKey[] = "ThemeName"; ThemeSettings::ThemeSettings() :
m_widget(0)
static QString customThemesPath()
{
QString path = Core::ICore::userResourcePath();
path.append(QLatin1String("/themes/"));
return path;
}
static QString createThemeFileName(const QString &pattern)
{
const QString stylesPath = customThemesPath();
QString baseFileName = stylesPath;
baseFileName += pattern;
// Find an available file name
int i = 1;
QString fileName;
do {
fileName = baseFileName.arg((i == 1) ? QString() : QString::number(i));
++i;
} while (QFile::exists(fileName));
// Create the base directory when it doesn't exist
if (!QFile::exists(stylesPath) && !QDir().mkpath(stylesPath)) {
qWarning() << "Failed to create theme directory:" << stylesPath;
return QString();
}
return fileName;
}
struct ThemeEntry
{
ThemeEntry() {}
ThemeEntry(const QString &fileName, bool readOnly):
m_fileName(fileName),
m_readOnly(readOnly)
{ }
QString fileName() const { return m_fileName; }
QString name() const;
bool readOnly() const { return m_readOnly; }
private:
QString m_fileName;
bool m_readOnly;
};
QString ThemeEntry::name() const
{
QSettings settings(m_fileName, QSettings::IniFormat);
QString n = settings.value(QLatin1String(themeNameKey), QCoreApplication::tr("unnamed")).toString();
return m_readOnly ? QCoreApplication::tr("%1 (built-in)").arg(n) : n;
}
class ThemeListModel : public QAbstractListModel
{
public:
ThemeListModel(QObject *parent = 0):
QAbstractListModel(parent)
{
}
int rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_themes.size();
}
QVariant data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
return m_themes.at(index.row()).name();
return QVariant();
}
void removeTheme(int index)
{
beginRemoveRows(QModelIndex(), index, index);
m_themes.removeAt(index);
endRemoveRows();
}
void setThemes(const QList<ThemeEntry> &themes)
{
beginResetModel();
m_themes = themes;
endResetModel();
}
const ThemeEntry &themeAt(int index) const
{
return m_themes.at(index);
}
private:
QList<ThemeEntry> m_themes;
};
class ThemeSettingsPrivate
{
public:
ThemeSettingsPrivate();
~ThemeSettingsPrivate();
public:
ThemeListModel *m_themeListModel;
bool m_refreshingThemeList;
Ui::ThemeSettings *m_ui;
QPointer<QWidget> m_widget;
ThemeEntry m_currentTheme;
};
ThemeSettingsPrivate::ThemeSettingsPrivate()
: m_themeListModel(new ThemeListModel)
, m_refreshingThemeList(false)
, m_ui(0)
{
m_currentTheme = ThemeEntry(creatorTheme()->fileName(), true);
}
ThemeSettingsPrivate::~ThemeSettingsPrivate()
{
delete m_themeListModel;
}
ThemeSettings::ThemeSettings()
{ {
setId(Core::Constants::SETTINGS_ID_ENVIRONMENT); setId(Core::Constants::SETTINGS_ID_ENVIRONMENT);
setDisplayName(tr("Theme")); setDisplayName(tr("Theme"));
setCategory(Core::Constants::SETTINGS_CATEGORY_CORE); setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
setDisplayCategory(QCoreApplication::translate("Core", Core::Constants::SETTINGS_TR_CATEGORY_CORE)); setDisplayCategory(QCoreApplication::translate("Core", Core::Constants::SETTINGS_TR_CATEGORY_CORE));
setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON)); setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON));
d = new ThemeSettingsPrivate();
} }
ThemeSettings::~ThemeSettings() ThemeSettings::~ThemeSettings()
{ {
delete d; delete m_widget;
}
void ThemeSettings::refreshThemeList()
{
QList<ThemeEntry> themes;
QString resourcePath = Core::ICore::resourcePath();
QDir themeDir(resourcePath + QLatin1String("/themes"));
themeDir.setNameFilters(QStringList() << QLatin1String("*.creatortheme"));
themeDir.setFilter(QDir::Files);
int selected = 0;
QStringList themeList = themeDir.entryList();
QString defaultTheme = QFileInfo(defaultThemeFileName()).fileName();
if (themeList.removeAll(defaultTheme))
themeList.prepend(defaultTheme);
foreach (const QString &file, themeList) {
const QString fileName = themeDir.absoluteFilePath(file);
if (d->m_currentTheme.fileName() == fileName)
selected = themes.size();
themes.append(ThemeEntry(fileName, true));
}
if (themes.isEmpty())
qWarning() << "Warning: no themes found in path:" << themeDir.path();
themeDir.setPath(customThemesPath());
foreach (const QString &file, themeDir.entryList()) {
const QString fileName = themeDir.absoluteFilePath(file);
if (d->m_currentTheme.fileName() == fileName)
selected = themes.size();
themes.append(ThemeEntry(fileName, false));
}
d->m_currentTheme = themes[selected];
d->m_refreshingThemeList = true;
d->m_themeListModel->setThemes(themes);
d->m_ui->themeComboBox->setCurrentIndex(selected);
d->m_refreshingThemeList = false;
}
QString ThemeSettings::defaultThemeFileName(const QString &fileName)
{
QString defaultScheme = Core::ICore::resourcePath();
defaultScheme += QLatin1String("/themes/");
if (!fileName.isEmpty() && QFile::exists(defaultScheme + fileName))
defaultScheme += fileName;
else
defaultScheme += QLatin1String("default.creatortheme");
return defaultScheme;
}
void ThemeSettings::themeSelected(int index)
{
bool readOnly = true;
if (index != -1) {
// Check whether we're switching away from a changed theme
if (!d->m_refreshingThemeList)
maybeSaveTheme();
const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
readOnly = entry.readOnly();
d->m_currentTheme = entry;
QSettings settings(entry.fileName(), QSettings::IniFormat);
Theme theme;
theme.readSettings(settings);
d->m_ui->editor->initFrom(&theme);
}
d->m_ui->copyButton->setEnabled(index != -1);
d->m_ui->deleteButton->setEnabled(!readOnly);
d->m_ui->renameButton->setEnabled(!readOnly);
d->m_ui->editor->setReadOnly(readOnly);
} }
QWidget *ThemeSettings::widget() QWidget *ThemeSettings::widget()
{ {
if (!d->m_widget) { if (!m_widget)
d->m_widget = new QWidget; m_widget = new ThemeSettingsWidget;
d->m_ui = new Ui::ThemeSettings(); return m_widget;
d->m_ui->setupUi(d->m_widget);
d->m_ui->themeComboBox->setModel(d->m_themeListModel);
connect(d->m_ui->themeComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &ThemeSettings::themeSelected);
connect(d->m_ui->copyButton, &QAbstractButton::clicked, this, &ThemeSettings::copyTheme);
connect(d->m_ui->renameButton, &QAbstractButton::clicked, this, &ThemeSettings::renameTheme);
connect(d->m_ui->deleteButton, &QAbstractButton::clicked, this, &ThemeSettings::confirmDeleteTheme);
refreshThemeList();
}
return d->m_widget;
}
void ThemeSettings::confirmDeleteTheme()
{
const int index = d->m_ui->themeComboBox->currentIndex();
if (index == -1)
return;
const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
if (entry.readOnly())
return;
QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning,
tr("Delete Theme"),
tr("Are you sure you want to delete the theme '%1' permanently?").arg(entry.name()),
QMessageBox::Discard | QMessageBox::Cancel,
d->m_ui->deleteButton->window());
// Change the text and role of the discard button
QPushButton *deleteButton = static_cast<QPushButton*>(messageBox->button(QMessageBox::Discard));
deleteButton->setText(tr("Delete"));
messageBox->addButton(deleteButton, QMessageBox::AcceptRole);
messageBox->setDefaultButton(deleteButton);
connect(deleteButton, &QAbstractButton::clicked, messageBox, &QDialog::accept);
connect(messageBox, &QDialog::accepted, this, &ThemeSettings::deleteTheme);
messageBox->setAttribute(Qt::WA_DeleteOnClose);
messageBox->open();
}
void ThemeSettings::deleteTheme()
{
const int index = d->m_ui->themeComboBox->currentIndex();
QTC_ASSERT(index != -1, return);
const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
QTC_ASSERT(!entry.readOnly(), return);
if (QFile::remove(entry.fileName()))
d->m_themeListModel->removeTheme(index);
}
void ThemeSettings::copyTheme()
{
QInputDialog *dialog = new QInputDialog(d->m_ui->copyButton->window());
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setInputMode(QInputDialog::TextInput);
dialog->setWindowTitle(tr("Copy Theme"));
dialog->setLabelText(tr("Theme name:"));
//TODO
//dialog->setTextValue(tr("%1 (copy)").arg(d_ptr->m_value.colorScheme().displayName()));
connect(dialog, &QInputDialog::textValueSelected, this, &ThemeSettings::copyThemeByName);
dialog->open();
}
void ThemeSettings::maybeSaveTheme()
{
if (!d->m_ui->editor->model()->hasChanges())
return;
QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning,
tr("Theme Changed"),
tr("The theme \"%1\" was modified, do you want to save the changes?")
.arg(d->m_currentTheme.name()),
QMessageBox::Discard | QMessageBox::Save,
d->m_ui->themeComboBox->window());
// Change the text of the discard button
QPushButton *discardButton = static_cast<QPushButton*>(messageBox->button(QMessageBox::Discard));
discardButton->setText(tr("Discard"));
messageBox->addButton(discardButton, QMessageBox::DestructiveRole);
messageBox->setDefaultButton(QMessageBox::Save);
if (messageBox->exec() == QMessageBox::Save) {
Theme newTheme;
d->m_ui->editor->model()->toTheme(&newTheme);
newTheme.writeSettings(d->m_currentTheme.fileName());
}
}
void ThemeSettings::renameTheme()
{
int index = d->m_ui->themeComboBox->currentIndex();
if (index == -1)
return;
const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
maybeSaveTheme();
QInputDialog *dialog = new QInputDialog(d->m_ui->renameButton->window());
dialog->setInputMode(QInputDialog::TextInput);
dialog->setWindowTitle(tr("Rename Theme"));
dialog->setLabelText(tr("Theme name:"));
dialog->setTextValue(d->m_ui->editor->model()->m_name);
int ret = dialog->exec();
QString newName = dialog->textValue();
delete dialog;
if (ret != QDialog::Accepted || newName.isEmpty())
return;
// overwrite file with new name
Theme newTheme;
d->m_ui->editor->model()->toTheme(&newTheme);
newTheme.setName(newName);
newTheme.writeSettings(entry.fileName());
refreshThemeList();
}
void ThemeSettings::copyThemeByName(const QString &name)
{
int index = d->m_ui->themeComboBox->currentIndex();
if (index == -1)
return;
const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
QString baseFileName = QFileInfo(entry.fileName()).completeBaseName();
baseFileName += QLatin1String("_copy%1.creatortheme");
QString fileName = createThemeFileName(baseFileName);
if (fileName.isEmpty())
return;
// Ask about saving any existing modifactions
maybeSaveTheme();
Theme newTheme;
d->m_ui->editor->model()->toTheme(&newTheme);
newTheme.setName(name);
newTheme.writeSettings(fileName);
d->m_currentTheme = ThemeEntry(fileName, true);
refreshThemeList();
} }
void ThemeSettings::apply() void ThemeSettings::apply()
{ {
if (!d->m_ui) // wasn't shown, can't be changed if (m_widget)
return; m_widget->apply();
{
d->m_ui->editor->model()->toTheme(creatorTheme());
if (creatorTheme()->flag(Theme::ApplyThemePaletteGlobally))
QApplication::setPalette(creatorTheme()->palette(QApplication::palette()));
foreach (QWidget *w, QApplication::topLevelWidgets())
w->update();
}
// save definition of theme
if (!d->m_currentTheme.readOnly()) {
Theme newTheme;
d->m_ui->editor->model()->toTheme(&newTheme);
newTheme.writeSettings(d->m_currentTheme.fileName());
}
// save filename of selected theme in global config
QSettings *settings = Core::ICore::settings();
settings->setValue(QLatin1String(Core::Constants::SETTINGS_THEME), d->m_currentTheme.fileName());
} }
void ThemeSettings::finish() void ThemeSettings::finish()
{ {
delete d->m_widget; delete m_widget;
if (!d->m_ui) // page was never shown m_widget = 0;
return
delete d->m_ui;
d->m_ui = 0;
} }
} // namespace Internal } // namespace Internal

View File

@@ -36,7 +36,7 @@
namespace Core { namespace Core {
namespace Internal { namespace Internal {
class ThemeSettingsPrivate; class ThemeSettingsWidget;
class ThemeSettings : public IOptionsPage class ThemeSettings : public IOptionsPage
{ {
@@ -50,20 +50,7 @@ public:
void apply(); void apply();
void finish(); void finish();
static QString defaultThemeFileName(const QString &fileName = QString()); ThemeSettingsWidget *m_widget;
private slots:
void themeSelected(int index);
void copyTheme();
void renameTheme();
void copyThemeByName(const QString &);
void confirmDeleteTheme();
void deleteTheme();
void maybeSaveTheme();
private:
void refreshThemeList();
ThemeSettingsPrivate *d;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -2,15 +2,19 @@
<ui version="4.0"> <ui version="4.0">
<class>Core::Internal::ThemeSettings</class> <class>Core::Internal::ThemeSettings</class>
<widget class="QWidget" name="Core::Internal::ThemeSettings"> <widget class="QWidget" name="Core::Internal::ThemeSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>527</width>
<height>359</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
@@ -66,8 +70,6 @@
<container>1</container> <container>1</container>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources> <resources/>
<include location="core.qrc"/>
</resources>
<connections/> <connections/>
</ui> </ui>

View File

@@ -0,0 +1,440 @@
/****************************************************************************
**
** Copyright (C) 2014 Thorben Kroeger <thorbenkroeger@gmail.com>.
** 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://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** 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 "themesettingswidget.h"
#include "coreconstants.h"
#include "icore.h"
#include "themeeditor/themesettingstablemodel.h"
#include <utils/theme/theme.h>
#include <utils/qtcassert.h>
#include <QDebug>
#include <QDir>
#include <QInputDialog>
#include <QMessageBox>
#include <QSettings>
#include "ui_themesettings.h"
using namespace Utils;
namespace Core {
namespace Internal {
const char themeNameKey[] = "ThemeName";
static QString customThemesPath()
{
QString path = Core::ICore::userResourcePath();
path.append(QLatin1String("/themes/"));
return path;
}
static QString createThemeFileName(const QString &pattern)
{
const QString stylesPath = customThemesPath();
QString baseFileName = stylesPath;
baseFileName += pattern;
// Find an available file name
int i = 1;
QString fileName;
do {
fileName = baseFileName.arg((i == 1) ? QString() : QString::number(i));
++i;
} while (QFile::exists(fileName));
// Create the base directory when it doesn't exist
if (!QFile::exists(stylesPath) && !QDir().mkpath(stylesPath)) {
qWarning() << "Failed to create theme directory:" << stylesPath;
return QString();
}
return fileName;
}
struct ThemeEntry
{
ThemeEntry() {}
ThemeEntry(const QString &fileName, bool readOnly):
m_fileName(fileName),
m_readOnly(readOnly)
{ }
QString fileName() const { return m_fileName; }
QString name() const;
bool readOnly() const { return m_readOnly; }
private:
QString m_fileName;
bool m_readOnly;
};
QString ThemeEntry::name() const
{
QSettings settings(m_fileName, QSettings::IniFormat);
QString n = settings.value(QLatin1String(themeNameKey), QCoreApplication::tr("unnamed")).toString();
return m_readOnly ? QCoreApplication::tr("%1 (built-in)").arg(n) : n;
}
class ThemeListModel : public QAbstractListModel
{
public:
ThemeListModel(QObject *parent = 0):
QAbstractListModel(parent)
{
}
int rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_themes.size();
}
QVariant data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
return m_themes.at(index.row()).name();
return QVariant();
}
void removeTheme(int index)
{
beginRemoveRows(QModelIndex(), index, index);
m_themes.removeAt(index);
endRemoveRows();
}
void setThemes(const QList<ThemeEntry> &themes)
{
beginResetModel();
m_themes = themes;
endResetModel();
}
const ThemeEntry &themeAt(int index) const
{
return m_themes.at(index);
}
private:
QList<ThemeEntry> m_themes;
};
class ThemeSettingsPrivate
{
public:
ThemeSettingsPrivate(QWidget *widget);
~ThemeSettingsPrivate();
public:
ThemeListModel *m_themeListModel;
bool m_refreshingThemeList;
Ui::ThemeSettings *m_ui;
ThemeEntry m_currentTheme;
};
ThemeSettingsPrivate::ThemeSettingsPrivate(QWidget *widget)
: m_themeListModel(new ThemeListModel)
, m_refreshingThemeList(false)
, m_ui(new Ui::ThemeSettings)
{
m_currentTheme = ThemeEntry(creatorTheme()->fileName(), true);
m_ui->setupUi(widget);
m_ui->editor->hide(); // TODO: Restore after improving the editor
m_ui->themeComboBox->setModel(m_themeListModel);
}
ThemeSettingsPrivate::~ThemeSettingsPrivate()
{
delete m_themeListModel;
delete m_ui;
}
ThemeSettingsWidget::ThemeSettingsWidget(QWidget *parent) :
QWidget(parent)
{
d = new ThemeSettingsPrivate(this);
connect(d->m_ui->themeComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &ThemeSettingsWidget::themeSelected);
connect(d->m_ui->copyButton, &QAbstractButton::clicked, this, &ThemeSettingsWidget::copyTheme);
connect(d->m_ui->renameButton, &QAbstractButton::clicked, this, &ThemeSettingsWidget::renameTheme);
connect(d->m_ui->deleteButton, &QAbstractButton::clicked, this, &ThemeSettingsWidget::confirmDeleteTheme);
refreshThemeList();
}
ThemeSettingsWidget::~ThemeSettingsWidget()
{
delete d;
}
void ThemeSettingsWidget::refreshThemeList()
{
QList<ThemeEntry> themes;
QString resourcePath = Core::ICore::resourcePath();
QDir themeDir(resourcePath + QLatin1String("/themes"));
themeDir.setNameFilters(QStringList() << QLatin1String("*.creatortheme"));
themeDir.setFilter(QDir::Files);
int selected = 0;
QStringList themeList = themeDir.entryList();
QString defaultTheme = QFileInfo(defaultThemeFileName()).fileName();
if (themeList.removeAll(defaultTheme))
themeList.prepend(defaultTheme);
foreach (const QString &file, themeList) {
const QString fileName = themeDir.absoluteFilePath(file);
if (d->m_currentTheme.fileName() == fileName)
selected = themes.size();
themes.append(ThemeEntry(fileName, true));
}
if (themes.isEmpty())
qWarning() << "Warning: no themes found in path:" << themeDir.path();
themeDir.setPath(customThemesPath());
foreach (const QString &file, themeDir.entryList()) {
const QString fileName = themeDir.absoluteFilePath(file);
if (d->m_currentTheme.fileName() == fileName)
selected = themes.size();
themes.append(ThemeEntry(fileName, false));
}
d->m_currentTheme = themes[selected];
d->m_refreshingThemeList = true;
d->m_themeListModel->setThemes(themes);
d->m_ui->themeComboBox->setCurrentIndex(selected);
d->m_refreshingThemeList = false;
}
QString ThemeSettingsWidget::defaultThemeFileName(const QString &fileName)
{
QString defaultScheme = Core::ICore::resourcePath();
defaultScheme += QLatin1String("/themes/");
if (!fileName.isEmpty() && QFile::exists(defaultScheme + fileName))
defaultScheme += fileName;
else
defaultScheme += QLatin1String("default.creatortheme");
return defaultScheme;
}
void ThemeSettingsWidget::themeSelected(int index)
{
bool readOnly = true;
if (index != -1) {
// Check whether we're switching away from a changed theme
if (!d->m_refreshingThemeList)
maybeSaveTheme();
const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
readOnly = entry.readOnly();
d->m_currentTheme = entry;
QSettings settings(entry.fileName(), QSettings::IniFormat);
Theme theme;
theme.readSettings(settings);
d->m_ui->editor->initFrom(&theme);
}
d->m_ui->copyButton->setEnabled(index != -1);
d->m_ui->deleteButton->setEnabled(!readOnly);
d->m_ui->renameButton->setEnabled(!readOnly);
d->m_ui->editor->setReadOnly(readOnly);
}
void ThemeSettingsWidget::confirmDeleteTheme()
{
const int index = d->m_ui->themeComboBox->currentIndex();
if (index == -1)
return;
const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
if (entry.readOnly())
return;
QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning,
tr("Delete Theme"),
tr("Are you sure you want to delete the theme '%1' permanently?").arg(entry.name()),
QMessageBox::Discard | QMessageBox::Cancel,
d->m_ui->deleteButton->window());
// Change the text and role of the discard button
QPushButton *deleteButton = static_cast<QPushButton*>(messageBox->button(QMessageBox::Discard));
deleteButton->setText(tr("Delete"));
messageBox->addButton(deleteButton, QMessageBox::AcceptRole);
messageBox->setDefaultButton(deleteButton);
connect(deleteButton, &QAbstractButton::clicked, messageBox, &QDialog::accept);
connect(messageBox, &QDialog::accepted, this, &ThemeSettingsWidget::deleteTheme);
messageBox->setAttribute(Qt::WA_DeleteOnClose);
messageBox->open();
}
void ThemeSettingsWidget::deleteTheme()
{
const int index = d->m_ui->themeComboBox->currentIndex();
QTC_ASSERT(index != -1, return);
const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
QTC_ASSERT(!entry.readOnly(), return);
if (QFile::remove(entry.fileName()))
d->m_themeListModel->removeTheme(index);
}
void ThemeSettingsWidget::copyTheme()
{
QInputDialog *dialog = new QInputDialog(d->m_ui->copyButton->window());
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setInputMode(QInputDialog::TextInput);
dialog->setWindowTitle(tr("Copy Theme"));
dialog->setLabelText(tr("Theme name:"));
//TODO
//dialog->setTextValue(tr("%1 (copy)").arg(d_ptr->m_value.colorScheme().displayName()));
connect(dialog, &QInputDialog::textValueSelected, this, &ThemeSettingsWidget::copyThemeByName);
dialog->open();
}
void ThemeSettingsWidget::maybeSaveTheme()
{
if (!d->m_ui->editor->model()->hasChanges())
return;
QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning,
tr("Theme Changed"),
tr("The theme \"%1\" was modified, do you want to save the changes?")
.arg(d->m_currentTheme.name()),
QMessageBox::Discard | QMessageBox::Save,
d->m_ui->themeComboBox->window());
// Change the text of the discard button
QPushButton *discardButton = static_cast<QPushButton*>(messageBox->button(QMessageBox::Discard));
discardButton->setText(tr("Discard"));
messageBox->addButton(discardButton, QMessageBox::DestructiveRole);
messageBox->setDefaultButton(QMessageBox::Save);
if (messageBox->exec() == QMessageBox::Save) {
Theme newTheme;
d->m_ui->editor->model()->toTheme(&newTheme);
newTheme.writeSettings(d->m_currentTheme.fileName());
}
}
void ThemeSettingsWidget::renameTheme()
{
int index = d->m_ui->themeComboBox->currentIndex();
if (index == -1)
return;
const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
maybeSaveTheme();
QInputDialog *dialog = new QInputDialog(d->m_ui->renameButton->window());
dialog->setInputMode(QInputDialog::TextInput);
dialog->setWindowTitle(tr("Rename Theme"));
dialog->setLabelText(tr("Theme name:"));
dialog->setTextValue(d->m_ui->editor->model()->m_name);
int ret = dialog->exec();
QString newName = dialog->textValue();
delete dialog;
if (ret != QDialog::Accepted || newName.isEmpty())
return;
// overwrite file with new name
Theme newTheme;
d->m_ui->editor->model()->toTheme(&newTheme);
newTheme.setName(newName);
newTheme.writeSettings(entry.fileName());
refreshThemeList();
}
void ThemeSettingsWidget::copyThemeByName(const QString &name)
{
int index = d->m_ui->themeComboBox->currentIndex();
if (index == -1)
return;
const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
QString baseFileName = QFileInfo(entry.fileName()).completeBaseName();
baseFileName += QLatin1String("_copy%1.creatortheme");
QString fileName = createThemeFileName(baseFileName);
if (fileName.isEmpty())
return;
// Ask about saving any existing modifactions
maybeSaveTheme();
Theme newTheme;
d->m_ui->editor->model()->toTheme(&newTheme);
newTheme.setName(name);
newTheme.writeSettings(fileName);
d->m_currentTheme = ThemeEntry(fileName, true);
refreshThemeList();
}
void ThemeSettingsWidget::apply()
{
{
d->m_ui->editor->model()->toTheme(creatorTheme());
if (creatorTheme()->flag(Theme::ApplyThemePaletteGlobally))
QApplication::setPalette(creatorTheme()->palette(QApplication::palette()));
foreach (QWidget *w, QApplication::topLevelWidgets())
w->update();
}
// save definition of theme
if (!d->m_currentTheme.readOnly()) {
Theme newTheme;
d->m_ui->editor->model()->toTheme(&newTheme);
newTheme.writeSettings(d->m_currentTheme.fileName());
}
// save filename of selected theme in global config
QSettings *settings = Core::ICore::settings();
settings->setValue(QLatin1String(Core::Constants::SETTINGS_THEME), d->m_currentTheme.fileName());
}
} // namespace Internal
} // namespace Core

View File

@@ -0,0 +1,70 @@
/****************************************************************************
**
** Copyright (C) 2014 Thorben Kroeger <thorbenkroeger@gmail.com>.
** 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://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** 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 THEMESETTINGSWIDGET_H
#define THEMESETTINGSWIDGET_H
#include <QWidget>
namespace Core {
namespace Internal {
class ThemeSettingsPrivate;
class ThemeSettingsWidget : public QWidget
{
Q_OBJECT
public:
ThemeSettingsWidget(QWidget *parent = 0);
~ThemeSettingsWidget();
static QString defaultThemeFileName(const QString &fileName = QString());
void apply();
private slots:
void themeSelected(int index);
void copyTheme();
void renameTheme();
void copyThemeByName(const QString &);
void confirmDeleteTheme();
void deleteTheme();
void maybeSaveTheme();
private:
void refreshThemeList();
ThemeSettingsPrivate *d;
};
} // namespace Internal
} // namespace Core
#endif // THEMESETTINGSWIDGET_H

View File

@@ -567,6 +567,8 @@ bool VariableChooser::eventFilter(QObject *obj, QEvent *event)
return handleEscapePressed(ke, this); return handleEscapePressed(ke, this);
} else if (event->type() == QEvent::Resize) { } else if (event->type() == QEvent::Resize) {
d->updateButtonGeometry(); d->updateButtonGeometry();
} else if (event->type() == QEvent::Hide) {
close();
} }
return false; return false;
} }

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "CodePaster" name: "CodePaster"

View File

@@ -1,5 +1,4 @@
import qbs 1.0 import qbs 1.0
import QtcTool
QtcTool { QtcTool {
name: "cpaster" name: "cpaster"

View File

@@ -1365,9 +1365,8 @@ void CppCodeModelInspectorDialog::refresh()
if (editor) { if (editor) {
const QString editorFilePath = editor->document()->filePath(); const QString editorFilePath = editor->document()->filePath();
editorDocument = cmmi->editorDocument(editorFilePath); editorDocument = cmmi->editorDocument(editorFilePath);
if (editorDocument) { if (auto *builtinDocumentParser = BuiltinEditorDocumentParser::get(editorFilePath)) {
const CPlusPlus::Snapshot editorSnapshot const CPlusPlus::Snapshot editorSnapshot = builtinDocumentParser->snapshot();
= BuiltinEditorDocumentParser::get(editorFilePath)->snapshot();
m_snapshotInfos->append(SnapshotInfo(editorSnapshot, SnapshotInfo::EditorSnapshot)); m_snapshotInfos->append(SnapshotInfo(editorSnapshot, SnapshotInfo::EditorSnapshot));
const QString editorSnapshotTitle const QString editorSnapshotTitle
= QString::fromLatin1("Current Editor's Snapshot (%1 Documents)") = QString::fromLatin1("Current Editor's Snapshot (%1 Documents)")

View File

@@ -1,8 +1,6 @@
import qbs 1.0 import qbs 1.0
import qbs.FileInfo import qbs.FileInfo
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "CppEditor" name: "CppEditor"

View File

@@ -100,6 +100,9 @@ private slots:
void test_FollowSymbolUnderCursor_data(); void test_FollowSymbolUnderCursor_data();
void test_FollowSymbolUnderCursor(); void test_FollowSymbolUnderCursor();
void test_FollowSymbolUnderCursor_followCall_data();
void test_FollowSymbolUnderCursor_followCall();
void test_FollowSymbolUnderCursor_QObject_connect_data(); void test_FollowSymbolUnderCursor_QObject_connect_data();
void test_FollowSymbolUnderCursor_QObject_connect(); void test_FollowSymbolUnderCursor_QObject_connect();

View File

@@ -931,45 +931,6 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_data()
"};\n" "};\n"
); );
QTest::newRow("matchFunctionSignature_FollowCall_1") << _(
"class Bar {};\n"
"void $foo(int) {}\n"
"void foo(const char *) {}\n"
"void foo(const Bar &) {}\n"
"void foo(char) {}\n"
"\n"
"void t()\n"
"{\n"
" @foo(5);\n"
"}\n"
);
QTest::newRow("matchFunctionSignature_FollowCall_2") << _(
"class Bar {};\n"
"void foo(int) {}\n"
"void $foo(const char *) {}\n"
"void foo(const Bar &) {}\n"
"void foo(char) {}\n"
"\n"
"void t()\n"
"{\n"
" @foo(\"hoo\");\n"
"}\n"
);
QTest::newRow("matchFunctionSignature_FollowCall_3") << _(
"class Bar {};\n"
"void foo(int) {}\n"
"void foo(const char *) {}\n"
"void foo(const Bar &) {}\n"
"void $foo(char) {}\n"
"\n"
"void t()\n"
"{\n"
" @foo('a');\n"
"}\n"
);
QTest::newRow("infiniteLoopLocalTypedef_QTCREATORBUG-11999") << _( QTest::newRow("infiniteLoopLocalTypedef_QTCREATORBUG-11999") << _(
"template<class MyTree>\n" "template<class MyTree>\n"
"class TreeConstIterator\n" "class TreeConstIterator\n"
@@ -993,6 +954,73 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor()
F2TestCase(F2TestCase::FollowSymbolUnderCursorAction, singleDocument(source)); F2TestCase(F2TestCase::FollowSymbolUnderCursorAction, singleDocument(source));
} }
void CppEditorPlugin::test_FollowSymbolUnderCursor_followCall_data()
{
QTest::addColumn<QByteArray>("variableDeclaration"); // without semicolon, can be ""
QTest::addColumn<QByteArray>("callArgument");
QTest::addColumn<QByteArray>("expectedSignature"); // you might need to add a function
// declaration with such a signature
QTest::newRow("intLiteral-to-int")
<< _("")
<< _("5")
<< _("int");
QTest::newRow("charLiteral-to-const-char-ptr")
<< _("")
<< _("\"hoo\"")
<< _("const char *");
QTest::newRow("charLiteral-to-int")
<< _("")
<< _("'a'")
<< _("char");
QTest::newRow("charPtr-to-constCharPtr")
<< _("char *var = \"var\"")
<< _("var")
<< _("const char *");
QTest::newRow("charPtr-to-constCharPtr")
<< _("char *var = \"var\"")
<< _("var")
<< _("const char *");
QTest::newRow("constCharPtr-to-constCharPtr")
<< _("const char *var = \"var\"")
<< _("var")
<< _("const char *");
QTest::newRow("Bar-to-constBarRef")
<< _("Bar var")
<< _("var")
<< _("const Bar &");
}
void CppEditorPlugin::test_FollowSymbolUnderCursor_followCall()
{
QFETCH(QByteArray, variableDeclaration);
QFETCH(QByteArray, callArgument);
QFETCH(QByteArray, expectedSignature);
const QByteArray templateSource =
"class Bar {};\n"
"void fun(int);\n"
"void fun(const char *);\n"
"void fun(const Bar &);\n"
"void fun(char);\n"
"void fun(double);\n"
"\n"
"void t()\n"
"{\n"
" " + variableDeclaration + ";\n"
" @fun(" + callArgument + ");\n"
"}\n";
const QByteArray matchText = " fun(" + expectedSignature + ")";
const QByteArray replaceText = " $fun(" + expectedSignature + ")";
QByteArray source = templateSource;
source.replace(matchText, replaceText);
QVERIFY(source != templateSource);
F2TestCase(F2TestCase::FollowSymbolUnderCursorAction, singleDocument(source));
}
void CppEditorPlugin::test_FollowSymbolUnderCursor_multipleDocuments_data() void CppEditorPlugin::test_FollowSymbolUnderCursor_multipleDocuments_data()
{ {
QTest::addColumn<QList<TestDocumentPtr> >("documents"); QTest::addColumn<QList<TestDocumentPtr> >("documents");

View File

@@ -629,21 +629,9 @@ public:
, m_newSourceFiles(newProjectInfo.sourceFiles()) , m_newSourceFiles(newProjectInfo.sourceFiles())
{} {}
bool definesChanged() const bool definesChanged() const { return m_new.definesChanged(m_old); }
{ bool configurationChanged() const { return m_new.configurationChanged(m_old); }
return m_new.defines() != m_old.defines(); bool configurationOrFilesChanged() const { return m_new.configurationOrFilesChanged(m_old); }
}
bool configurationChanged() const
{
return definesChanged()
|| m_new.headerPaths() != m_old.headerPaths();
}
bool nothingChanged() const
{
return !configurationChanged() && m_new.sourceFiles() == m_old.sourceFiles();
}
QSet<QString> addedFiles() const QSet<QString> addedFiles() const
{ {
@@ -735,8 +723,12 @@ QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo &newProjectIn
ProjectInfo oldProjectInfo = d->m_projectToProjectsInfo.value(project); ProjectInfo oldProjectInfo = d->m_projectToProjectsInfo.value(project);
if (oldProjectInfo.isValid()) { if (oldProjectInfo.isValid()) {
ProjectInfoComparer comparer(oldProjectInfo, newProjectInfo); ProjectInfoComparer comparer(oldProjectInfo, newProjectInfo);
if (comparer.nothingChanged())
if (!comparer.configurationOrFilesChanged()) {
// Some other attached data might have changed
d->m_projectToProjectsInfo.insert(project, newProjectInfo);
return QFuture<void>(); return QFuture<void>();
}
// If the project configuration changed, do a full reindexing // If the project configuration changed, do a full reindexing
if (comparer.configurationChanged()) { if (comparer.configurationChanged()) {

View File

@@ -49,6 +49,7 @@ ProjectPart::ProjectPart()
, languageExtensions(NoExtensions) , languageExtensions(NoExtensions)
, qtVersion(UnknownQt) , qtVersion(UnknownQt)
, warningFlags(ProjectExplorer::ToolChain::WarningsDefault) , warningFlags(ProjectExplorer::ToolChain::WarningsDefault)
, selectedForBuilding(true)
{ {
} }
@@ -137,6 +138,36 @@ ProjectInfo::ProjectInfo(QPointer<ProjectExplorer::Project> project)
: m_project(project) : m_project(project)
{} {}
bool ProjectInfo::operator ==(const ProjectInfo &other) const
{
return m_project == other.m_project
&& m_projectParts == other.m_projectParts
&& m_compilerCallData == other.m_compilerCallData
&& m_headerPaths == other.m_headerPaths
&& m_sourceFiles == other.m_sourceFiles
&& m_defines == other.m_defines;
}
bool ProjectInfo::operator !=(const ProjectInfo &other) const
{
return !operator ==(other);
}
bool ProjectInfo::definesChanged(const ProjectInfo &other) const
{
return m_defines != other.m_defines;
}
bool ProjectInfo::configurationChanged(const ProjectInfo &other) const
{
return definesChanged(other) || m_headerPaths != other.m_headerPaths;
}
bool ProjectInfo::configurationOrFilesChanged(const ProjectInfo &other) const
{
return configurationChanged(other) || m_sourceFiles != other.m_sourceFiles;
}
bool ProjectInfo::isValid() const bool ProjectInfo::isValid() const
{ {
return !m_project.isNull(); return !m_project.isNull();
@@ -193,6 +224,7 @@ void ProjectInfo::clearProjectParts()
m_headerPaths.clear(); m_headerPaths.clear();
m_sourceFiles.clear(); m_sourceFiles.clear();
m_defines.clear(); m_defines.clear();
m_compilerCallData.clear();
} }
const ProjectPart::HeaderPaths ProjectInfo::headerPaths() const const ProjectPart::HeaderPaths ProjectInfo::headerPaths() const
@@ -210,6 +242,16 @@ const QByteArray ProjectInfo::defines() const
return m_defines; return m_defines;
} }
void ProjectInfo::setCompilerCallData(const CompilerCallData &data)
{
m_compilerCallData = data;
}
ProjectInfo::CompilerCallData ProjectInfo::compilerCallData() const
{
return m_compilerCallData;
}
namespace { namespace {
class ProjectFileCategorizer class ProjectFileCategorizer
{ {

View File

@@ -129,6 +129,7 @@ public: // fields
LanguageExtensions languageExtensions; LanguageExtensions languageExtensions;
QtVersion qtVersion; QtVersion qtVersion;
ProjectExplorer::ToolChain::WarningFlags warningFlags; ProjectExplorer::ToolChain::WarningFlags warningFlags;
bool selectedForBuilding;
}; };
inline uint qHash(const ProjectPart::HeaderPath &key, uint seed = 0) inline uint qHash(const ProjectPart::HeaderPath &key, uint seed = 0)
@@ -142,6 +143,12 @@ public:
bool isValid() const; bool isValid() const;
bool operator ==(const ProjectInfo &other) const;
bool operator !=(const ProjectInfo &other) const;
bool definesChanged(const ProjectInfo &other) const;
bool configurationChanged(const ProjectInfo &other) const;
bool configurationOrFilesChanged(const ProjectInfo &other) const;
QPointer<ProjectExplorer::Project> project() const; QPointer<ProjectExplorer::Project> project() const;
const QList<ProjectPart::Ptr> projectParts() const; const QList<ProjectPart::Ptr> projectParts() const;
@@ -153,10 +160,16 @@ public:
const QSet<QString> sourceFiles() const; const QSet<QString> sourceFiles() const;
const QByteArray defines() const; const QByteArray defines() const;
// Source file --> List of compiler calls
typedef QHash<QString, QList<QStringList>> CompilerCallData;
void setCompilerCallData(const CompilerCallData &data);
CompilerCallData compilerCallData() const;
private: private:
QPointer<ProjectExplorer::Project> m_project; QPointer<ProjectExplorer::Project> m_project;
QList<ProjectPart::Ptr> m_projectParts; QList<ProjectPart::Ptr> m_projectParts;
// The members below are (re)calculated from the project parts once a part is appended. CompilerCallData m_compilerCallData;
// The members below are (re)calculated from the project parts with finish()
ProjectPart::HeaderPaths m_headerPaths; ProjectPart::HeaderPaths m_headerPaths;
QSet<QString> m_sourceFiles; QSet<QString> m_sourceFiles;
QByteArray m_defines; QByteArray m_defines;

View File

@@ -1,8 +1,6 @@
import qbs 1.0 import qbs 1.0
import qbs.FileInfo import qbs.FileInfo
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "CppTools" name: "CppTools"

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "CVS" name: "CVS"

View File

@@ -190,7 +190,6 @@ static inline bool fileNameMatch(const QString &f1, const QString &f2)
static bool isSimilarTo(const BreakpointParameters &data, const BreakpointResponse &needle) static bool isSimilarTo(const BreakpointParameters &data, const BreakpointResponse &needle)
{ {
// Clear hit.
// Clear miss. // Clear miss.
if (needle.type != UnknownBreakpointType && data.type != UnknownBreakpointType if (needle.type != UnknownBreakpointType && data.type != UnknownBreakpointType
&& data.type != needle.type) && data.type != needle.type)
@@ -200,6 +199,10 @@ static bool isSimilarTo(const BreakpointParameters &data, const BreakpointRespon
if (data.address && data.address == needle.address) if (data.address && data.address == needle.address)
return true; return true;
// Clear hit.
if (data == needle)
return true;
// At least at a position we were looking for. // At least at a position we were looking for.
// FIXME: breaks multiple breakpoints at the same location // FIXME: breaks multiple breakpoints at the same location
if (!data.fileName.isEmpty() if (!data.fileName.isEmpty()

View File

@@ -1,7 +1,5 @@
import qbs 1.0 import qbs 1.0
import QtcPlugin
QtcPlugin { QtcPlugin {
name: "Debugger" name: "Debugger"

View File

@@ -1140,14 +1140,13 @@ public:
DebuggerEngine *m_currentEngine; DebuggerEngine *m_currentEngine;
DebuggerSettings *m_debuggerSettings; DebuggerSettings *m_debuggerSettings;
QStringList m_arguments; QStringList m_arguments;
DebuggerToolTipManager *m_toolTipManager; DebuggerToolTipManager m_toolTipManager;
CommonOptionsPage *m_commonOptionsPage; CommonOptionsPage *m_commonOptionsPage;
DummyEngine *m_dummyEngine; DummyEngine *m_dummyEngine;
const QSharedPointer<GlobalDebuggerOptions> m_globalDebuggerOptions; const QSharedPointer<GlobalDebuggerOptions> m_globalDebuggerOptions;
}; };
DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) : DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) :
m_toolTipManager(new DebuggerToolTipManager(this)),
m_dummyEngine(0), m_dummyEngine(0),
m_globalDebuggerOptions(new GlobalDebuggerOptions) m_globalDebuggerOptions(new GlobalDebuggerOptions)
{ {
@@ -2036,7 +2035,7 @@ void DebuggerPluginPrivate::setInitialState()
setBusyCursor(false); setBusyCursor(false);
m_reverseDirectionAction->setChecked(false); m_reverseDirectionAction->setChecked(false);
m_reverseDirectionAction->setEnabled(false); m_reverseDirectionAction->setEnabled(false);
m_toolTipManager->closeAllToolTips(); m_toolTipManager.closeAllToolTips();
m_startAndDebugApplicationAction->setEnabled(true); m_startAndDebugApplicationAction->setEnabled(true);
m_attachToQmlPortAction->setEnabled(true); m_attachToQmlPortAction->setEnabled(true);
@@ -2269,14 +2268,14 @@ void DebuggerPluginPrivate::onModeChanged(IMode *mode)
m_mainWindow->onModeChanged(mode); m_mainWindow->onModeChanged(mode);
if (mode->id() != Constants::MODE_DEBUG) { if (mode->id() != Constants::MODE_DEBUG) {
m_toolTipManager->leavingDebugMode(); m_toolTipManager.leavingDebugMode();
return; return;
} }
if (IEditor *editor = EditorManager::currentEditor()) if (IEditor *editor = EditorManager::currentEditor())
editor->widget()->setFocus(); editor->widget()->setFocus();
m_toolTipManager->debugModeEntered(); m_toolTipManager.debugModeEntered();
} }
void DebuggerPluginPrivate::showSettingsDialog() void DebuggerPluginPrivate::showSettingsDialog()
@@ -2334,7 +2333,7 @@ void DebuggerPluginPrivate::sessionLoaded()
void DebuggerPluginPrivate::aboutToUnloadSession() void DebuggerPluginPrivate::aboutToUnloadSession()
{ {
m_toolTipManager->sessionAboutToChange(); m_toolTipManager.sessionAboutToChange();
} }
void DebuggerPluginPrivate::aboutToSaveSession() void DebuggerPluginPrivate::aboutToSaveSession()

View File

@@ -65,31 +65,45 @@
using namespace Core; using namespace Core;
using namespace TextEditor; using namespace TextEditor;
namespace Debugger {
namespace Internal {
class DebuggerToolTipWidget;
QList<QPointer<DebuggerToolTipWidget>> m_tooltips;
bool m_debugModeActive;
// Expire tooltips after n days on (no longer load them) in order // Expire tooltips after n days on (no longer load them) in order
// to avoid them piling up. // to avoid them piling up.
enum { toolTipsExpiryDays = 6 }; enum { toolTipsExpiryDays = 6 };
static const char sessionSettingsKeyC[] = "DebuggerToolTips"; const char sessionSettingsKeyC[] = "DebuggerToolTips";
static const char sessionDocumentC[] = "DebuggerToolTips"; const char sessionDocumentC[] = "DebuggerToolTips";
static const char sessionVersionAttributeC[] = "version"; const char sessionVersionAttributeC[] = "version";
static const char toolTipElementC[] = "DebuggerToolTip"; const char toolTipElementC[] = "DebuggerToolTip";
static const char toolTipClassAttributeC[] = "class"; const char toolTipClassAttributeC[] = "class";
static const char fileNameAttributeC[] = "name"; const char fileNameAttributeC[] = "name";
static const char functionAttributeC[] = "function"; const char functionAttributeC[] = "function";
static const char textPositionAttributeC[] = "position"; const char textPositionAttributeC[] = "position";
static const char textLineAttributeC[] = "line"; const char textLineAttributeC[] = "line";
static const char textColumnAttributeC[] = "column"; const char textColumnAttributeC[] = "column";
static const char offsetXAttributeC[] = "offset_x"; const char offsetXAttributeC[] = "offset_x";
static const char offsetYAttributeC[] = "offset_y"; const char offsetYAttributeC[] = "offset_y";
static const char engineTypeAttributeC[] = "engine"; const char engineTypeAttributeC[] = "engine";
static const char dateAttributeC[] = "date"; const char dateAttributeC[] = "date";
static const char treeElementC[] = "tree"; const char treeElementC[] = "tree";
static const char treeExpressionAttributeC[] = "expression"; const char treeExpressionAttributeC[] = "expression";
static const char treeInameAttributeC[] = "iname"; const char treeInameAttributeC[] = "iname";
static const char modelElementC[] = "model"; const char modelElementC[] = "model";
static const char modelColumnCountAttributeC[] = "columncount"; const char modelColumnCountAttributeC[] = "columncount";
static const char modelRowElementC[] = "row"; const char modelRowElementC[] = "row";
static const char modelItemElementC[] = "item"; const char modelItemElementC[] = "item";
static void purgeClosedToolTips()
{
for (int i = m_tooltips.size(); --i >= 0; )
if (!m_tooltips.at(i))
m_tooltips.removeAt(i);
}
// Forward a stream reader across end elements looking for the // Forward a stream reader across end elements looking for the
// next start element of a desired type. // next start element of a desired type.
@@ -112,19 +126,6 @@ static bool readStartElement(QXmlStreamReader &r, const char *name)
return true; return true;
} }
#if 0
static void debugMode(const QAbstractItemModel *model)
{
QDebug nospace = qDebug().nospace();
nospace << model << '\n';
for (int r = 0; r < model->rowCount(); r++)
nospace << '#' << r << ' ' << model->data(model->index(r, 0)).toString() << '\n';
}
#endif
namespace Debugger {
namespace Internal {
// A label that can be dragged to drag something else. // A label that can be dragged to drag something else.
class DraggableLabel : public QLabel class DraggableLabel : public QLabel
@@ -472,27 +473,134 @@ private:
StandardItemTreeModelBuilder m_builder; StandardItemTreeModelBuilder m_builder;
}; };
class DebuggerToolTipWidget; /*!
\class Debugger::Internal::DebuggerToolTipTreeView
class DebuggerToolTipManagerData \brief The DebuggerToolTipTreeView class is a treeview that adapts its size
to the model contents (also while expanding)
to be used within DebuggerTreeViewToolTipWidget.
*/
class DebuggerToolTipTreeView : public QTreeView
{ {
public: public:
DebuggerToolTipManagerData() explicit DebuggerToolTipTreeView(QWidget *parent = 0);
: m_debugModeActive(false)
{}
void purgeClosedToolTips() QSize sizeHint() const { return m_size; }
{
for (int i = m_tooltips.size(); --i >= 0; )
if (!m_tooltips.at(i))
m_tooltips.removeAt(i);
}
QList<QPointer<DebuggerToolTipWidget> > m_tooltips; void computeSize();
bool m_debugModeActive;
private:
void expandNode(const QModelIndex &idx);
void collapseNode(const QModelIndex &idx);
int computeHeight(const QModelIndex &index) const;
QSize m_size;
}; };
static DebuggerToolTipManagerData *d = 0; DebuggerToolTipTreeView::DebuggerToolTipTreeView(QWidget *parent) :
QTreeView(parent)
{
setHeaderHidden(true);
setEditTriggers(NoEditTriggers);
setUniformRowHeights(true);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
connect(this, &QTreeView::collapsed, this, &DebuggerToolTipTreeView::computeSize,
Qt::QueuedConnection);
connect(this, &QTreeView::expanded, this, &DebuggerToolTipTreeView::computeSize,
Qt::QueuedConnection);
connect(this, &QTreeView::expanded,
this, &DebuggerToolTipTreeView::expandNode);
connect(this, &QTreeView::collapsed,
this, &DebuggerToolTipTreeView::collapseNode);
}
void DebuggerToolTipTreeView::expandNode(const QModelIndex &idx)
{
model()->setData(idx, true, LocalsExpandedRole);
}
void DebuggerToolTipTreeView::collapseNode(const QModelIndex &idx)
{
model()->setData(idx, false, LocalsExpandedRole);
}
int DebuggerToolTipTreeView::computeHeight(const QModelIndex &index) const
{
int s = rowHeight(index);
const int rowCount = model()->rowCount(index);
for (int i = 0; i < rowCount; ++i)
s += computeHeight(model()->index(i, 0, index));
return s;
}
void DebuggerToolTipTreeView::computeSize()
{
int columns = 30; // Decoration
int rows = 0;
bool rootDecorated = false;
if (QAbstractItemModel *m = model()) {
WatchTreeView::reexpand(this, m->index(0, 0));
const int columnCount = m->columnCount();
rootDecorated = m->rowCount() > 0;
if (rootDecorated)
for (int i = 0; i < columnCount; ++i) {
resizeColumnToContents(i);
columns += sizeHintForColumn(i);
}
if (columns < 100)
columns = 100; // Prevent toolbar from shrinking when displaying 'Previous'
rows += computeHeight(QModelIndex());
// Fit tooltip to screen, showing/hiding scrollbars as needed.
// Add a bit of space to account for tooltip border, and not
// touch the border of the screen.
QPoint pos(x(), y());
QTC_ASSERT(QApplication::desktop(), return);
QRect desktopRect = QApplication::desktop()->availableGeometry(pos);
const int maxWidth = desktopRect.right() - pos.x() - 5 - 5;
const int maxHeight = desktopRect.bottom() - pos.y() - 5 - 5;
if (columns > maxWidth)
rows += horizontalScrollBar()->height();
if (rows > maxHeight) {
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
rows = maxHeight;
columns += verticalScrollBar()->width();
} else {
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
if (columns > maxWidth) {
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
columns = maxWidth;
} else {
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
}
m_size = QSize(columns + 5, rows + 5);
setMinimumSize(m_size);
setMaximumSize(m_size);
setRootIsDecorated(rootDecorated);
}
QString DebuggerToolTipManager::treeModelClipboardContents(const QAbstractItemModel *model)
{
QString rc;
QTC_ASSERT(model, return rc);
QTextStream str(&rc);
DumpTreeModelVisitor v(model, DumpTreeModelVisitor::ClipboardMode, str);
v.run();
return rc;
}
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
@@ -503,8 +611,6 @@ static DebuggerToolTipManagerData *d = 0;
class DebuggerToolTipWidget : public QWidget class DebuggerToolTipWidget : public QWidget
{ {
Q_OBJECT
public: public:
DebuggerToolTipWidget(const DebuggerToolTipContext &context); DebuggerToolTipWidget(const DebuggerToolTipContext &context);
@@ -519,10 +625,13 @@ public:
void releaseEngine(); void releaseEngine();
void saveSessionData(QXmlStreamWriter &w) const; void saveSessionData(QXmlStreamWriter &w) const;
void setWatchModel(QAbstractItemModel *watchModel); void setWatchModel(WatchModelBase *watchModel);
void handleStackFrameCompleted(const QString &frameFile, const QString &frameFunction); void handleStackFrameCompleted(const QString &frameFile, const QString &frameFunction);
public slots: void copy();
void positionShow(const TextEditorWidget *editorWidget);
void pin();
void handleItemIsExpanded(const QModelIndex &sourceIdx) void handleItemIsExpanded(const QModelIndex &sourceIdx)
{ {
QTC_ASSERT(m_filterModel.sourceModel() == sourceIdx.model(), return); QTC_ASSERT(m_filterModel.sourceModel() == sourceIdx.model(), return);
@@ -531,10 +640,6 @@ public slots:
m_treeView->expand(mappedIdx); m_treeView->expand(mappedIdx);
} }
void copy();
void positionShow(const TextEditorWidget *editorWidget);
void pin();
public: public:
bool m_isPinned; bool m_isPinned;
QToolButton *m_toolButton; QToolButton *m_toolButton;
@@ -546,6 +651,13 @@ public:
QStandardItemModel m_defaultModel; QStandardItemModel m_defaultModel;
}; };
static void hideAllToolTips()
{
purgeClosedToolTips();
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
tw->hide();
}
void DebuggerToolTipWidget::pin() void DebuggerToolTipWidget::pin()
{ {
if (m_isPinned) if (m_isPinned)
@@ -662,6 +774,7 @@ DebuggerToolTipWidget::DebuggerToolTipWidget(const DebuggerToolTipContext &conte
m_titleLabel = new DraggableLabel(this); m_titleLabel = new DraggableLabel(this);
m_titleLabel->setText(msgReleasedText()); m_titleLabel->setText(msgReleasedText());
m_titleLabel->setMinimumWidth(40); // Ensure a draggable area even if text is empty. m_titleLabel->setMinimumWidth(40); // Ensure a draggable area even if text is empty.
m_titleLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
auto toolBar = new QToolBar(this); auto toolBar = new QToolBar(this);
toolBar->setProperty("_q_custom_style_disabled", QVariant(true)); toolBar->setProperty("_q_custom_style_disabled", QVariant(true));
@@ -669,8 +782,8 @@ DebuggerToolTipWidget::DebuggerToolTipWidget(const DebuggerToolTipContext &conte
if (!pinIconSizes.isEmpty()) if (!pinIconSizes.isEmpty())
toolBar->setIconSize(pinIconSizes.front()); toolBar->setIconSize(pinIconSizes.front());
toolBar->addWidget(m_toolButton); toolBar->addWidget(m_toolButton);
toolBar->addWidget(m_titleLabel);
toolBar->addWidget(copyButton); toolBar->addWidget(copyButton);
toolBar->addWidget(m_titleLabel);
m_treeView = new DebuggerToolTipTreeView(this); m_treeView = new DebuggerToolTipTreeView(this);
m_treeView->setFocusPolicy(Qt::NoFocus); m_treeView->setFocusPolicy(Qt::NoFocus);
@@ -691,14 +804,14 @@ DebuggerToolTipWidget::DebuggerToolTipWidget(const DebuggerToolTipContext &conte
connect(copyButton, &QAbstractButton::clicked, this, &DebuggerToolTipWidget::copy); connect(copyButton, &QAbstractButton::clicked, this, &DebuggerToolTipWidget::copy);
} }
void DebuggerToolTipWidget::setWatchModel(QAbstractItemModel *watchModel) void DebuggerToolTipWidget::setWatchModel(WatchModelBase *watchModel)
{ {
QTC_ASSERT(watchModel, return); QTC_ASSERT(watchModel, return);
m_filterModel.setSourceModel(watchModel); m_filterModel.setSourceModel(watchModel);
connect(watchModel, SIGNAL(itemIsExpanded(QModelIndex)), connect(watchModel, &WatchModelBase::itemIsExpanded,
this, SLOT(handleItemIsExpanded(QModelIndex)), Qt::UniqueConnection); this, &DebuggerToolTipWidget::handleItemIsExpanded, Qt::UniqueConnection);
connect(watchModel, SIGNAL(columnAdjustmentRequested()), connect(watchModel, &WatchModelBase::columnAdjustmentRequested,
m_treeView, SLOT(computeSize()), Qt::UniqueConnection); m_treeView, &DebuggerToolTipTreeView::computeSize, Qt::UniqueConnection);
} }
void DebuggerToolTipWidget::handleStackFrameCompleted(const QString &frameFile, const QString &frameFunction) void DebuggerToolTipWidget::handleStackFrameCompleted(const QString &frameFile, const QString &frameFunction)
@@ -780,7 +893,7 @@ void DebuggerToolTipWidget::positionShow(const TextEditorWidget *editorWidget)
static DebuggerToolTipWidget *findOrCreateWidget(const DebuggerToolTipContext &context) static DebuggerToolTipWidget *findOrCreateWidget(const DebuggerToolTipContext &context)
{ {
foreach (const QPointer<DebuggerToolTipWidget> &tw, d->m_tooltips) foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
if (tw && tw->m_context.isSame(context)) if (tw && tw->m_context.isSame(context))
return tw; return tw;
@@ -789,7 +902,7 @@ static DebuggerToolTipWidget *findOrCreateWidget(const DebuggerToolTipContext &c
tw->setObjectName(QLatin1String("DebuggerTreeViewToolTipWidget: ") + QLatin1String(context.iname)); tw->setObjectName(QLatin1String("DebuggerTreeViewToolTipWidget: ") + QLatin1String(context.iname));
tw->m_context.creationDate = QDate::currentDate(); tw->m_context.creationDate = QDate::currentDate();
d->m_tooltips.push_back(tw); m_tooltips.push_back(tw);
return tw; return tw;
} }
@@ -839,7 +952,7 @@ static QDate dateFromString(const QString &date)
QDate(); QDate();
} }
static void loadSessionDataI(QXmlStreamReader &r) static void loadSessionDataHelper(QXmlStreamReader &r)
{ {
if (!readStartElement(r, toolTipElementC)) if (!readStartElement(r, toolTipElementC))
return; return;
@@ -919,118 +1032,6 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
w.writeEndElement(); w.writeEndElement();
} }
/*!
\class Debugger::Internal::DebuggerToolTipTreeView
\brief The DebuggerToolTipTreeView class is a treeview that adapts its size
to the model contents (also while expanding)
to be used within DebuggerTreeViewToolTipWidget.
*/
DebuggerToolTipTreeView::DebuggerToolTipTreeView(QWidget *parent) :
QTreeView(parent)
{
setHeaderHidden(true);
setEditTriggers(NoEditTriggers);
setUniformRowHeights(true);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
connect(this, SIGNAL(collapsed(QModelIndex)), this, SLOT(computeSize()),
Qt::QueuedConnection);
connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(computeSize()),
Qt::QueuedConnection);
connect(this, SIGNAL(expanded(QModelIndex)),
SLOT(expandNode(QModelIndex)));
connect(this, SIGNAL(collapsed(QModelIndex)),
SLOT(collapseNode(QModelIndex)));
}
void DebuggerToolTipTreeView::expandNode(const QModelIndex &idx)
{
model()->setData(idx, true, LocalsExpandedRole);
}
void DebuggerToolTipTreeView::collapseNode(const QModelIndex &idx)
{
model()->setData(idx, false, LocalsExpandedRole);
}
int DebuggerToolTipTreeView::computeHeight(const QModelIndex &index) const
{
int s = rowHeight(index);
const int rowCount = model()->rowCount(index);
for (int i = 0; i < rowCount; ++i)
s += computeHeight(model()->index(i, 0, index));
return s;
}
void DebuggerToolTipTreeView::computeSize()
{
int columns = 30; // Decoration
int rows = 0;
bool rootDecorated = false;
if (QAbstractItemModel *m = model()) {
WatchTreeView::reexpand(this, m->index(0, 0));
const int columnCount = m->columnCount();
rootDecorated = m->rowCount() > 0;
if (rootDecorated)
for (int i = 0; i < columnCount; ++i) {
resizeColumnToContents(i);
columns += sizeHintForColumn(i);
}
if (columns < 100)
columns = 100; // Prevent toolbar from shrinking when displaying 'Previous'
rows += computeHeight(QModelIndex());
// Fit tooltip to screen, showing/hiding scrollbars as needed.
// Add a bit of space to account for tooltip border, and not
// touch the border of the screen.
QPoint pos(x(), y());
QTC_ASSERT(QApplication::desktop(), return);
QRect desktopRect = QApplication::desktop()->availableGeometry(pos);
const int maxWidth = desktopRect.right() - pos.x() - 5 - 5;
const int maxHeight = desktopRect.bottom() - pos.y() - 5 - 5;
if (columns > maxWidth)
rows += horizontalScrollBar()->height();
if (rows > maxHeight) {
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
rows = maxHeight;
columns += verticalScrollBar()->width();
} else {
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
if (columns > maxWidth) {
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
columns = maxWidth;
} else {
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
}
m_size = QSize(columns + 5, rows + 5);
setMinimumSize(m_size);
setMaximumSize(m_size);
setRootIsDecorated(rootDecorated);
}
QString DebuggerToolTipManager::treeModelClipboardContents(const QAbstractItemModel *model)
{
QString rc;
QTC_ASSERT(model, return rc);
QTextStream str(&rc);
DumpTreeModelVisitor v(model, DumpTreeModelVisitor::ClipboardMode, str);
v.run();
return rc;
}
/*! /*!
\class Debugger::Internal::DebuggerToolTipManager \class Debugger::Internal::DebuggerToolTipManager
@@ -1046,19 +1047,13 @@ QString DebuggerToolTipManager::treeModelClipboardContents(const QAbstractItemMo
(by file name and function) acquire the engine, others release. (by file name and function) acquire the engine, others release.
*/ */
static DebuggerToolTipManager *m_instance = 0;
DebuggerToolTipManager::DebuggerToolTipManager(QObject *parent) : DebuggerToolTipManager::DebuggerToolTipManager()
QObject(parent)
{ {
d = new DebuggerToolTipManagerData;
m_instance = this;
} }
DebuggerToolTipManager::~DebuggerToolTipManager() DebuggerToolTipManager::~DebuggerToolTipManager()
{ {
delete d;
m_instance = 0;
} }
void DebuggerToolTipManager::registerEngine(DebuggerEngine *) void DebuggerToolTipManager::registerEngine(DebuggerEngine *)
@@ -1066,11 +1061,42 @@ void DebuggerToolTipManager::registerEngine(DebuggerEngine *)
loadSessionData(); loadSessionData();
} }
void DebuggerToolTipManager::slotUpdateVisibleToolTips()
{
purgeClosedToolTips();
if (m_tooltips.isEmpty())
return;
if (!m_debugModeActive) {
hideAllToolTips();
return;
}
BaseTextEditor *toolTipEditor = BaseTextEditor::currentTextEditor();
if (!toolTipEditor) {
hideAllToolTips();
return;
}
const QString fileName = toolTipEditor->textDocument()->filePath();
if (fileName.isEmpty()) {
hideAllToolTips();
return;
}
// Reposition and show all tooltips of that file.
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) {
if (tw->fileName() == fileName)
tw->positionShow(toolTipEditor->editorWidget());
else
tw->hide();
}
}
void DebuggerToolTipManager::updateEngine(DebuggerEngine *engine) void DebuggerToolTipManager::updateEngine(DebuggerEngine *engine)
{ {
QTC_ASSERT(engine, return); QTC_ASSERT(engine, return);
d->purgeClosedToolTips(); purgeClosedToolTips();
if (d->m_tooltips.isEmpty()) if (m_tooltips.isEmpty())
return; return;
// Stack frame changed: All tooltips of that file acquire the engine, // Stack frame changed: All tooltips of that file acquire the engine,
@@ -1085,7 +1111,7 @@ void DebuggerToolTipManager::updateEngine(DebuggerEngine *engine)
function = frame.function; function = frame.function;
} }
} }
foreach (const QPointer<DebuggerToolTipWidget> &tw, d->m_tooltips) foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
tw->handleStackFrameCompleted(fileName, function); tw->handleStackFrameCompleted(fileName, function);
slotUpdateVisibleToolTips(); // Move out when stepping in same file. slotUpdateVisibleToolTips(); // Move out when stepping in same file.
} }
@@ -1093,7 +1119,7 @@ void DebuggerToolTipManager::updateEngine(DebuggerEngine *engine)
void DebuggerToolTipManager::deregisterEngine(DebuggerEngine *engine) void DebuggerToolTipManager::deregisterEngine(DebuggerEngine *engine)
{ {
QTC_ASSERT(engine, return); QTC_ASSERT(engine, return);
foreach (const QPointer<DebuggerToolTipWidget> &tw, d->m_tooltips) foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
if (tw && tw->m_context.engineType == engine->objectName()) if (tw && tw->m_context.engineType == engine->objectName())
tw->releaseEngine(); tw->releaseEngine();
saveSessionData(); saveSessionData();
@@ -1101,7 +1127,7 @@ void DebuggerToolTipManager::deregisterEngine(DebuggerEngine *engine)
bool DebuggerToolTipManager::hasToolTips() bool DebuggerToolTipManager::hasToolTips()
{ {
return !d->m_tooltips.isEmpty(); return !m_tooltips.isEmpty();
} }
void DebuggerToolTipManager::showToolTip void DebuggerToolTipManager::showToolTip
@@ -1118,37 +1144,6 @@ void DebuggerToolTipManager::showToolTip
Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow()); Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow());
} }
bool DebuggerToolTipManager::eventFilter(QObject *o, QEvent *e)
{
if (!hasToolTips())
return false;
switch (e->type()) {
case QEvent::Move: { // Move along with parent (toplevel)
const QMoveEvent *me = static_cast<const QMoveEvent *>(e);
const QPoint dist = me->pos() - me->oldPos();
d->purgeClosedToolTips();
foreach (const QPointer<DebuggerToolTipWidget> &tw, d->m_tooltips)
if (tw->isVisible())
tw->move(tw->pos() + dist);
}
break;
case QEvent::WindowStateChange: { // Hide/Show along with parent (toplevel)
const QWindowStateChangeEvent *se = static_cast<const QWindowStateChangeEvent *>(e);
const bool wasMinimized = se->oldState() & Qt::WindowMinimized;
const bool isMinimized = static_cast<const QWidget *>(o)->windowState() & Qt::WindowMinimized;
if (wasMinimized ^ isMinimized) {
d->purgeClosedToolTips();
foreach (const QPointer<DebuggerToolTipWidget> &tw, d->m_tooltips)
tw->setVisible(!isMinimized);
}
}
break;
default:
break;
}
return false;
}
void DebuggerToolTipManager::sessionAboutToChange() void DebuggerToolTipManager::sessionAboutToChange()
{ {
closeAllToolTips(); closeAllToolTips();
@@ -1161,19 +1156,19 @@ void DebuggerToolTipManager::loadSessionData()
r.readNextStartElement(); r.readNextStartElement();
if (r.tokenType() == QXmlStreamReader::StartElement && r.name() == QLatin1String(sessionDocumentC)) if (r.tokenType() == QXmlStreamReader::StartElement && r.name() == QLatin1String(sessionDocumentC))
while (!r.atEnd()) while (!r.atEnd())
loadSessionDataI(r); loadSessionDataHelper(r);
} }
void DebuggerToolTipManager::saveSessionData() void DebuggerToolTipManager::saveSessionData()
{ {
QString data; QString data;
d->purgeClosedToolTips(); purgeClosedToolTips();
QXmlStreamWriter w(&data); QXmlStreamWriter w(&data);
w.writeStartDocument(); w.writeStartDocument();
w.writeStartElement(QLatin1String(sessionDocumentC)); w.writeStartElement(QLatin1String(sessionDocumentC));
w.writeAttribute(QLatin1String(sessionVersionAttributeC), QLatin1String("1.0")); w.writeAttribute(QLatin1String(sessionVersionAttributeC), QLatin1String("1.0"));
foreach (const QPointer<DebuggerToolTipWidget> &tw, d->m_tooltips) foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
if (tw->isPinned()) if (tw->isPinned())
tw->saveSessionData(w); tw->saveSessionData(w);
w.writeEndDocument(); w.writeEndDocument();
@@ -1183,119 +1178,13 @@ void DebuggerToolTipManager::saveSessionData()
void DebuggerToolTipManager::closeAllToolTips() void DebuggerToolTipManager::closeAllToolTips()
{ {
d->purgeClosedToolTips(); purgeClosedToolTips();
foreach (const QPointer<DebuggerToolTipWidget> &tw, d->m_tooltips) foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
tw->close(); tw->close();
d->m_tooltips.clear(); m_tooltips.clear();
} }
void DebuggerToolTipManager::hide() static void slotTooltipOverrideRequested
{
d->purgeClosedToolTips();
foreach (const QPointer<DebuggerToolTipWidget> &tw, d->m_tooltips)
tw->hide();
}
void DebuggerToolTipManager::slotUpdateVisibleToolTips()
{
d->purgeClosedToolTips();
if (d->m_tooltips.isEmpty())
return;
if (!d->m_debugModeActive) {
hide();
return;
}
BaseTextEditor *toolTipEditor = BaseTextEditor::currentTextEditor();
if (!toolTipEditor) {
hide();
return;
}
const QString fileName = toolTipEditor->textDocument()->filePath();
if (fileName.isEmpty()) {
hide();
return;
}
// Reposition and show all tooltips of that file.
foreach (const QPointer<DebuggerToolTipWidget> &tw, d->m_tooltips) {
if (tw->fileName() == fileName)
tw->positionShow(toolTipEditor->editorWidget());
else
tw->hide();
}
}
void DebuggerToolTipManager::slotDebuggerStateChanged(DebuggerState state)
{
const QObject *engine = sender();
QTC_ASSERT(engine, return);
// Release at earliest possible convenience.
switch (state) {
case InferiorShutdownRequested:
case EngineShutdownRequested:
case DebuggerFinished:
case EngineShutdownOk: {
break;
}
default:
break;
}
}
void DebuggerToolTipManager::slotEditorOpened(IEditor *e)
{
// Move tooltip along when scrolled.
if (BaseTextEditor *textEditor = qobject_cast<BaseTextEditor *>(e)) {
TextEditorWidget *widget = textEditor->editorWidget();
connect(widget->verticalScrollBar(), &QScrollBar::valueChanged,
this, &DebuggerToolTipManager::slotUpdateVisibleToolTips);
connect(widget, &TextEditorWidget::tooltipOverrideRequested,
this, &DebuggerToolTipManager::slotTooltipOverrideRequested);
}
}
void DebuggerToolTipManager::debugModeEntered()
{
// Hook up all signals in debug mode.
if (!d->m_debugModeActive) {
d->m_debugModeActive = true;
QWidget *topLevel = ICore::mainWindow()->topLevelWidget();
topLevel->installEventFilter(this);
EditorManager *em = EditorManager::instance();
connect(em, &EditorManager::currentEditorChanged,
this, &DebuggerToolTipManager::slotUpdateVisibleToolTips);
connect(em, &EditorManager::editorOpened,
this, &DebuggerToolTipManager::slotEditorOpened);
foreach (IEditor *e, DocumentModel::editorsForOpenedDocuments())
slotEditorOpened(e);
// Position tooltips delayed once all the editor placeholder layouting is done.
if (!d->m_tooltips.isEmpty())
QTimer::singleShot(0, this, SLOT(slotUpdateVisibleToolTips()));
}
}
void DebuggerToolTipManager::leavingDebugMode()
{
// Remove all signals in debug mode.
if (d->m_debugModeActive) {
d->m_debugModeActive = false;
hide();
if (QWidget *topLevel = ICore::mainWindow()->topLevelWidget())
topLevel->removeEventFilter(this);
foreach (IEditor *e, DocumentModel::editorsForOpenedDocuments()) {
if (BaseTextEditor *toolTipEditor = qobject_cast<BaseTextEditor *>(e)) {
toolTipEditor->editorWidget()->verticalScrollBar()->disconnect(this);
toolTipEditor->disconnect(this);
}
}
EditorManager::instance()->disconnect(this);
}
}
void DebuggerToolTipManager::slotTooltipOverrideRequested
(TextEditorWidget *editorWidget, const QPoint &point, int pos, bool *handled) (TextEditorWidget *editorWidget, const QPoint &point, int pos, bool *handled)
{ {
QTC_ASSERT(handled, return); QTC_ASSERT(handled, return);
@@ -1319,7 +1208,7 @@ void DebuggerToolTipManager::slotTooltipOverrideRequested
context.expression = fixCppExpression(raw); context.expression = fixCppExpression(raw);
if (context.expression.isEmpty()) { if (context.expression.isEmpty()) {
const Utils::WidgetContent widgetContent(new QLabel(tr("No valid expression")), true); const Utils::WidgetContent widgetContent(new QLabel(DebuggerToolTipManager::tr("No valid expression")), true);
Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow()); Utils::ToolTip::show(context.mousePosition, widgetContent, Internal::mainWindow());
*handled = true; *handled = true;
return; return;
@@ -1331,7 +1220,7 @@ void DebuggerToolTipManager::slotTooltipOverrideRequested
if (context.expression.isEmpty()) if (context.expression.isEmpty())
context.expression = localVariable->name; context.expression = localVariable->name;
context.iname = localVariable->iname; context.iname = localVariable->iname;
showToolTip(context, engine); DebuggerToolTipManager::showToolTip(context, engine);
*handled = true; *handled = true;
return; return;
} }
@@ -1345,18 +1234,97 @@ void DebuggerToolTipManager::slotTooltipOverrideRequested
} }
static void slotEditorOpened(IEditor *e)
{
// Move tooltip along when scrolled.
if (BaseTextEditor *textEditor = qobject_cast<BaseTextEditor *>(e)) {
TextEditorWidget *widget = textEditor->editorWidget();
QObject::connect(widget->verticalScrollBar(), &QScrollBar::valueChanged,
&DebuggerToolTipManager::slotUpdateVisibleToolTips);
QObject::connect(widget, &TextEditorWidget::tooltipOverrideRequested,
slotTooltipOverrideRequested);
}
}
void DebuggerToolTipManager::debugModeEntered()
{
// Hook up all signals in debug mode.
if (!m_debugModeActive) {
m_debugModeActive = true;
QWidget *topLevel = ICore::mainWindow()->topLevelWidget();
topLevel->installEventFilter(this);
EditorManager *em = EditorManager::instance();
connect(em, &EditorManager::currentEditorChanged,
&DebuggerToolTipManager::slotUpdateVisibleToolTips);
connect(em, &EditorManager::editorOpened, slotEditorOpened);
foreach (IEditor *e, DocumentModel::editorsForOpenedDocuments())
slotEditorOpened(e);
// Position tooltips delayed once all the editor placeholder layouting is done.
if (!m_tooltips.isEmpty())
QTimer::singleShot(0, this, SLOT(slotUpdateVisibleToolTips()));
}
}
void DebuggerToolTipManager::leavingDebugMode()
{
// Remove all signals in debug mode.
if (m_debugModeActive) {
m_debugModeActive = false;
hideAllToolTips();
if (QWidget *topLevel = ICore::mainWindow()->topLevelWidget())
topLevel->removeEventFilter(this);
foreach (IEditor *e, DocumentModel::editorsForOpenedDocuments()) {
if (BaseTextEditor *toolTipEditor = qobject_cast<BaseTextEditor *>(e)) {
toolTipEditor->editorWidget()->verticalScrollBar()->disconnect(this);
toolTipEditor->disconnect(this);
}
}
EditorManager::instance()->disconnect(this);
}
}
DebuggerToolTipContexts DebuggerToolTipManager::treeWidgetExpressions DebuggerToolTipContexts DebuggerToolTipManager::treeWidgetExpressions
(DebuggerEngine *, const QString &fileName, const QString &function) (DebuggerEngine *, const QString &fileName, const QString &function)
{ {
DebuggerToolTipContexts rc; DebuggerToolTipContexts rc;
foreach (const QPointer<DebuggerToolTipWidget> &tw, d->m_tooltips) { foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips) {
if (tw && tw->context().matchesFrame(fileName, function)) if (tw && tw->context().matchesFrame(fileName, function))
rc.push_back(tw->context()); rc.push_back(tw->context());
} }
return rc; return rc;
} }
bool DebuggerToolTipManager::eventFilter(QObject *o, QEvent *e)
{
if (m_tooltips.isEmpty())
return false;
switch (e->type()) {
case QEvent::Move: { // Move along with parent (toplevel)
const QMoveEvent *me = static_cast<const QMoveEvent *>(e);
const QPoint dist = me->pos() - me->oldPos();
purgeClosedToolTips();
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
if (tw->isVisible())
tw->move(tw->pos() + dist);
}
break;
case QEvent::WindowStateChange: { // Hide/Show along with parent (toplevel)
const QWindowStateChangeEvent *se = static_cast<const QWindowStateChangeEvent *>(e);
const bool wasMinimized = se->oldState() & Qt::WindowMinimized;
const bool isMinimized = static_cast<const QWidget *>(o)->windowState() & Qt::WindowMinimized;
if (wasMinimized ^ isMinimized) {
purgeClosedToolTips();
foreach (const QPointer<DebuggerToolTipWidget> &tw, m_tooltips)
tw->setVisible(!isMinimized);
}
}
break;
default:
break;
}
return false;
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger
#include "debuggertooltipmanager.moc"

View File

@@ -33,18 +33,16 @@
#include "debuggerconstants.h" #include "debuggerconstants.h"
#include <QCoreApplication>
#include <QDate> #include <QDate>
#include <QPointer> #include <QPoint>
#include <QTreeView>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QDebug; class QAbstractItemModel;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace Core { class IEditor; }
namespace TextEditor { class BaseTextEditor; class TextEditorWidget; }
namespace Debugger { namespace Debugger {
class DebuggerEngine; class DebuggerEngine;
namespace Internal { namespace Internal {
@@ -72,36 +70,12 @@ public:
typedef QList<DebuggerToolTipContext> DebuggerToolTipContexts; typedef QList<DebuggerToolTipContext> DebuggerToolTipContexts;
QDebug operator<<(QDebug, const DebuggerToolTipContext &);
class DebuggerToolTipTreeView : public QTreeView
{
Q_OBJECT
public:
explicit DebuggerToolTipTreeView(QWidget *parent = 0);
QAbstractItemModel *swapModel(QAbstractItemModel *model);
QSize sizeHint() const { return m_size; }
private slots:
void computeSize();
void expandNode(const QModelIndex &idx);
void collapseNode(const QModelIndex &idx);
private:
int computeHeight(const QModelIndex &index) const;
QSize m_size;
};
class DebuggerToolTipManager : public QObject class DebuggerToolTipManager : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit DebuggerToolTipManager(QObject *parent = 0); DebuggerToolTipManager();
~DebuggerToolTipManager(); ~DebuggerToolTipManager();
static void registerEngine(DebuggerEngine *engine); static void registerEngine(DebuggerEngine *engine);
@@ -120,21 +94,15 @@ public:
static QString treeModelClipboardContents(const QAbstractItemModel *model); static QString treeModelClipboardContents(const QAbstractItemModel *model);
public slots:
void debugModeEntered(); void debugModeEntered();
void leavingDebugMode(); void leavingDebugMode();
void sessionAboutToChange(); void sessionAboutToChange();
static void loadSessionData(); static void loadSessionData();
static void saveSessionData(); static void saveSessionData();
static void closeAllToolTips(); static void closeAllToolTips();
static void hide();
private slots: public slots:
static void slotUpdateVisibleToolTips(); static void slotUpdateVisibleToolTips();
void slotDebuggerStateChanged(Debugger::DebuggerState);
void slotEditorOpened(Core::IEditor *);
void slotTooltipOverrideRequested(TextEditor::TextEditorWidget *editorWidget,
const QPoint &point, int pos, bool *handled);
}; };
} // namespace Internal } // namespace Internal

Some files were not shown because too many files have changed in this diff Show More