diff --git a/outputview/outputfilteringstrategies.cpp b/outputview/outputfilteringstrategies.cpp
index 087a57696d..2f7c3bb35d 100644
--- a/outputview/outputfilteringstrategies.cpp
+++ b/outputview/outputfilteringstrategies.cpp
@@ -1,436 +1,451 @@
/*
This file is part of KDevelop
Copyright (C) 2012 Morten Danielsen Volden mvolden2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "outputfilteringstrategies.h"
#include "outputformats.h"
#include "filtereditem.h"
#include
#include
#include
#include
using namespace KDevelop;
namespace {
template
FilteredItem match(const ErrorFormats& errorFormats, const QString& line)
{
FilteredItem item(line);
for( const ErrorFormat& curErrFilter : errorFormats ) {
const auto match = curErrFilter.expression.match(line);
if( match.hasMatch() ) {
item.url = QUrl::fromUserInput(match.captured( curErrFilter.fileGroup ));
item.lineNo = match.captured( curErrFilter.lineGroup ).toInt() - 1;
if(curErrFilter.columnGroup >= 0) {
item.columnNo = match.captured( curErrFilter.columnGroup ).toInt() - 1;
} else {
item.columnNo = 0;
}
QString txt = match.captured(curErrFilter.textGroup);
item.type = FilteredItem::ErrorItem;
// Make the item clickable if it comes with the necessary file & line number information
if (curErrFilter.fileGroup > 0 && curErrFilter.lineGroup > 0) {
item.isActivatable = true;
}
break;
}
}
return item;
}
}
/// --- No filter strategy ---
NoFilterStrategy::NoFilterStrategy()
{
}
FilteredItem NoFilterStrategy::actionInLine(const QString& line)
{
return FilteredItem( line );
}
FilteredItem NoFilterStrategy::errorInLine(const QString& line)
{
return FilteredItem( line );
}
/// --- Compiler error filter strategy ---
CompilerFilterStrategy::CompilerFilterStrategy(const QUrl& buildDir)
: m_buildDir(buildDir)
{
}
Path CompilerFilterStrategy::pathForFile(const QString& filename) const
{
QFileInfo fi( filename );
Path currentPath;
if( fi.isRelative() ) {
if( m_currentDirs.isEmpty() ) {
return Path(m_buildDir, filename );
}
auto it = m_currentDirs.constEnd() - 1;
do {
currentPath = Path(*it, filename);
} while( (it-- != m_currentDirs.constBegin()) && !QFileInfo(currentPath.toLocalFile()).exists() );
return currentPath;
} else {
currentPath = Path(filename);
}
return currentPath;
}
bool CompilerFilterStrategy::isMultiLineCase(KDevelop::ErrorFormat curErrFilter) const
{
if(curErrFilter.compiler == QLatin1String("gfortran") || curErrFilter.compiler == QLatin1String("cmake")) {
return true;
}
return false;
}
void CompilerFilterStrategy::putDirAtEnd(const Path& pathToInsert)
{
auto it = m_positionInCurrentDirs.find( pathToInsert );
// Encountered new build directory?
if (it == m_positionInCurrentDirs.end()) {
m_currentDirs.push_back( pathToInsert );
m_positionInCurrentDirs.insert( pathToInsert, m_currentDirs.size() - 1 );
} else {
// Build dir already in currentDirs, but move it to back of currentDirs list
// (this gives us most-recently-used semantics in pathForFile)
std::rotate(m_currentDirs.begin() + it.value(), m_currentDirs.begin() + it.value() + 1, m_currentDirs.end() );
it.value() = m_currentDirs.size() - 1;
}
}
QVector CompilerFilterStrategy::getCurrentDirs()
{
QVector ret;
ret.reserve(m_currentDirs.size());
for (const auto& path : m_currentDirs) {
ret << path.pathOrUrl();
}
return ret;
}
FilteredItem CompilerFilterStrategy::actionInLine(const QString& line)
{
// A list of filters for possible compiler, linker, and make actions
static const ActionFormat ACTION_FILTERS[] = {
ActionFormat( ki18nc("compiling a file: %1 file %2 compiler", "compiling %1 (%2)"), 1, 2,
QStringLiteral("(?:^|[^=])\\b(gcc|CC|cc|distcc|c\\+\\+|g\\+\\+|clang(?:\\+\\+)|mpicc|icc|icpc)\\s+.*-c.*[/ '\\\\]+(\\w+\\.(?:cpp|CPP|c|C|cxx|CXX|cs|java|hpf|f|F|f90|F90|f95|F95))")),
//moc and uic
ActionFormat( ki18nc("generating a file: %1 file %2 generator tool", "generating %1 (%2)"), 1, 2,
QStringLiteral("/(moc|uic)\\b.*\\s-o\\s([^\\s;]+)")),
//libtool linking
ActionFormat( ki18nc("Linking object files into a library or executable: %1 target, %2 linker", "linking %1 (%2)"),
QStringLiteral("libtool"), QStringLiteral("/bin/sh\\s.*libtool.*--mode=link\\s.*\\s-o\\s([^\\s;]+)"), 1 ),
//unsermake
ActionFormat( ki18nc("compiling a file: %1 file %2 compiler", "compiling %1 (%2)"), 1, 1,
QStringLiteral("^compiling (.*)") ),
ActionFormat( ki18nc("generating a file: %1 file %2 generator tool", "generating %1 (%2)"), 1, 2,
QStringLiteral("^generating (.*)") ),
ActionFormat( ki18nc("Linking object files into a library or executable: %1 file, %2 linker", "linking %1 (%2)"), 1, 2,
QStringLiteral("(gcc|cc|c\\+\\+|g\\+\\+|clang(?:\\+\\+)|mpicc|icc|icpc)\\S* (?:\\S* )*-o ([^\\s;]+)")),
ActionFormat( ki18nc("Linking object files into a library or executable: %1 file, %2 compiler", "linking %1 (%2)"), 1, 2,
QStringLiteral("^linking (.*)") ),
//cmake
ActionFormat( ki18nc("finished building a target: %1 target name", "built %1"), -1, 1,
QStringLiteral("\\[.+%\\] Built target (.*)") ),
ActionFormat( ki18nc("compiling a file: %1 file %2 compiler", "compiling %1 (%2)"), QStringLiteral("cmake"),
QStringLiteral("\\[.+%\\] Building .* object (.*)"), 1 ),
ActionFormat( ki18nc("generating a file: %1 file %2 generator tool", "generating %1 (%2)"), -1, 1,
QStringLiteral("\\[.+%\\] Generating (.*)") ),
ActionFormat( ki18nc("Linking object files into a library or executable: %1 target", "linking %1"), -1, 1,
QStringLiteral("^Linking (.*)") ),
ActionFormat( ki18nc("configuring a project: %1 tool", "configuring (%1)"), QStringLiteral("cmake"),
QStringLiteral("(-- Configuring (done|incomplete)|-- Found|-- Adding|-- Enabling)"), -1 ),
ActionFormat( ki18nc("installing a file: %1 file", "installing %1"), -1, 1,
QStringLiteral("-- Installing (.*)") ),
//libtool install
ActionFormat( ki18nc("creating a folder: %1 path", "creating %1"), {},
QStringLiteral("/(?:bin/sh\\s.*mkinstalldirs).*\\s([^\\s;]+)"), 1 ),
ActionFormat( ki18nc("installing a file: %1 file", "installing %1"), {},
QStringLiteral("/(?:usr/bin/install|bin/sh\\s.*mkinstalldirs|bin/sh\\s.*libtool.*--mode=install).*\\s([^\\s;]+)"), 1 ),
//dcop
ActionFormat( ki18nc("generating a file: %1 file %2 generator tool", "generating %1 (%2)"), QStringLiteral("dcopidl"),
QStringLiteral("dcopidl .* > ([^\\s;]+)"), 1 ),
ActionFormat( ki18nc("compiling a file: %1 file %2 compiler", "compiling %1 (%2)"), QStringLiteral("dcopidl2cpp"),
QStringLiteral("dcopidl2cpp (?:\\S* )*([^\\s;]+)"), 1 ),
// match against Entering directory to update current build dir
ActionFormat( ki18nc("change directory: %1: path", "entering %1 (%2)"), QStringLiteral("cd"),
QStringLiteral("make\\[\\d+\\]: Entering directory (\\`|\\')(.+)'"), 2),
// waf and scons use the same basic convention as make
ActionFormat( ki18nc("change directory: %1: path", "entering %1 (%2)"), QStringLiteral("cd"),
QStringLiteral("(Waf|scons): Entering directory (\\`|\\')(.+)'"), 3)
};
FilteredItem item(line);
for (const auto& curActFilter : ACTION_FILTERS) {
const auto match = curActFilter.expression.match(line);
if( match.hasMatch() ) {
item.type = FilteredItem::ActionItem;
KLocalizedString shortened = curActFilter.label;
if (curActFilter.fileGroup != -1) {
shortened = shortened.subs(match.captured(curActFilter.fileGroup));
}
if (curActFilter.toolGroup != -1 ) {
shortened = shortened.subs(match.captured(curActFilter.toolGroup));
} else if (!curActFilter.tool.isEmpty()) {
shortened = shortened.subs(curActFilter.tool);
}
item.shortenedText = shortened.toString();
if( curActFilter.tool == "cd" ) {
const Path path(match.captured(curActFilter.fileGroup));
m_currentDirs.push_back( path );
m_positionInCurrentDirs.insert( path , m_currentDirs.size() - 1 );
}
// Special case for cmake: we parse the "Compiling " expression
// and use it to find out about the build paths encountered during a build.
// They are later searched by pathForFile to find source files corresponding to
// compiler errors.
// Note: CMake objectfile has the format: "/path/to/four/CMakeFiles/file.o"
if ( curActFilter.fileGroup != -1 && curActFilter.tool == "cmake" && line.contains("Building")) {
const auto objectFile = match.captured(curActFilter.fileGroup);
const auto dir = objectFile.section(QStringLiteral("CMakeFiles/"), 0, 0);
putDirAtEnd(Path(m_buildDir, dir));
}
break;
}
}
return item;
}
FilteredItem CompilerFilterStrategy::errorInLine(const QString& line)
{
// All the possible string that indicate an error if we via Regex have been able to
// extract file and linenumber from a given outputline
// TODO: This seems clumsy -- and requires another scan of the line.
// Merge this information into ErrorFormat? --Kevin
using Indicator = QPair;
static const Indicator INDICATORS[] = {
// ld
Indicator(QStringLiteral("undefined reference"), FilteredItem::ErrorItem),
Indicator(QStringLiteral("undefined symbol"), FilteredItem::ErrorItem),
Indicator(QStringLiteral("ld: cannot find"), FilteredItem::ErrorItem),
Indicator(QStringLiteral("no such file"), FilteredItem::ErrorItem),
// gcc
Indicator(QStringLiteral("error"), FilteredItem::ErrorItem),
// generic
Indicator(QStringLiteral("warning"), FilteredItem::WarningItem),
Indicator(QStringLiteral("info"), FilteredItem::InformationItem),
Indicator(QStringLiteral("note"), FilteredItem::InformationItem),
};
// A list of filters for possible compiler, linker, and make errors
static const ErrorFormat ERROR_FILTERS[] = {
#ifdef Q_OS_WIN
// MSVC
ErrorFormat( QStringLiteral("^([a-zA-Z]:\\\\.+)\\(([1-9][0-9]*)\\): ((?:error|warning) .+\\:).*$"), 1, 2, 3 ),
#endif
// GCC - another case, eg. for #include "pixmap.xpm" which does not exists
ErrorFormat( QStringLiteral("^([^:\t]+):([0-9]+):([0-9]+):([^0-9]+)"), 1, 2, 4, 3 ),
// GCC
ErrorFormat( QStringLiteral("^([^:\t]+):([0-9]+):([^0-9]+)"), 1, 2, 3 ),
// GCC
ErrorFormat( QStringLiteral("^(In file included from |[ ]+from )([^: \\t]+):([0-9]+)(:|,)(|[0-9]+)"), 2, 3, 5 ),
// ICC
ErrorFormat( QStringLiteral("^([^: \\t]+)\\(([0-9]+)\\):([^0-9]+)"), 1, 2, 3, QStringLiteral("intel") ),
//libtool link
ErrorFormat( QStringLiteral("^(libtool):( link):( warning): "), 0, 0, 0 ),
// make
ErrorFormat( QStringLiteral("No rule to make target"), 0, 0, 0 ),
// cmake
ErrorFormat( QStringLiteral("^([^: \\t]+):([0-9]+):"), 1, 2, 0, QStringLiteral("cmake") ),
// cmake
ErrorFormat( QStringLiteral("CMake (Error|Warning) (|\\([a-zA-Z]+\\) )(in|at) ([^:]+):($|[0-9]+)"), 4, 5, 1, QStringLiteral("cmake") ),
// cmake/automoc
// example: AUTOMOC: error: /foo/bar.cpp The file includes (...),
// example: AUTOMOC: error: /foo/bar.cpp: The file includes (...)
// note: ':' after file name isn't always appended, see http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=317d8498aa02c9f486bf5071963bb2034777cdd6
// example: AUTOGEN: error: /foo/bar.cpp: The file includes (...)
// note: AUTOMOC got renamed to AUTOGEN at some point
ErrorFormat( QStringLiteral("^(AUTOMOC|AUTOGEN): error: ([^:]+):? (The file .*)$"), 2, 0, 0 ),
// via qt4_automoc
// example: automoc4: The file "/foo/bar.cpp" includes the moc file "bar1.moc", but ...
ErrorFormat( QStringLiteral("^automoc4: The file \"([^\"]+)\" includes the moc file"), 1, 0, 0 ),
// Fortran
ErrorFormat( QStringLiteral("\"(.*)\", line ([0-9]+):(.*)"), 1, 2, 3 ),
// GFortran
ErrorFormat( QStringLiteral("^(.*):([0-9]+)\\.([0-9]+):(.*)"), 1, 2, 4, QStringLiteral("gfortran"), 3 ),
// Jade
ErrorFormat( QStringLiteral("^[a-zA-Z]+:([^: \t]+):([0-9]+):[0-9]+:[a-zA-Z]:(.*)"), 1, 2, 3 ),
// ifort
ErrorFormat( QStringLiteral("^fortcom: (.*): (.*), line ([0-9]+):(.*)"), 2, 3, 1, QStringLiteral("intel") ),
// PGI
ErrorFormat( QStringLiteral("PGF9(.*)-(.*)-(.*)-(.*) \\((.*): ([0-9]+)\\)"), 5, 6, 4, QStringLiteral("pgi") ),
// PGI (2)
ErrorFormat( QStringLiteral("PGF9(.*)-(.*)-(.*)-Symbol, (.*) \\((.*)\\)"), 5, 5, 4, QStringLiteral("pgi") ),
};
FilteredItem item(line);
for (const auto& curErrFilter : ERROR_FILTERS) {
const auto match = curErrFilter.expression.match(line);
if( match.hasMatch() && !( line.contains( QLatin1String("Each undeclared identifier is reported only once") )
|| line.contains( QLatin1String("for each function it appears in.") ) ) )
{
if(curErrFilter.fileGroup > 0) {
if( curErrFilter.compiler == "cmake" ) { // Unfortunately we cannot know if an error or an action comes first in cmake, and therefore we need to do this
if( m_currentDirs.empty() ) {
putDirAtEnd( m_buildDir.parent() );
}
}
item.url = pathForFile( match.captured( curErrFilter.fileGroup ) ).toUrl();
}
item.lineNo = match.captured( curErrFilter.lineGroup ).toInt() - 1;
if(curErrFilter.columnGroup >= 0) {
item.columnNo = match.captured( curErrFilter.columnGroup ).toInt() - 1;
} else {
item.columnNo = 0;
}
QString txt = match.captured(curErrFilter.textGroup);
// Find the indicator which happens most early.
int earliestIndicatorIdx = txt.length();
for (const auto& curIndicator : INDICATORS) {
int curIndicatorIdx = txt.indexOf(curIndicator.first, 0, Qt::CaseInsensitive);
if((curIndicatorIdx >= 0) && (earliestIndicatorIdx > curIndicatorIdx)) {
earliestIndicatorIdx = curIndicatorIdx;
item.type = curIndicator.second;
}
}
// Make the item clickable if it comes with the necessary file information
if (item.url.isValid()) {
item.isActivatable = true;
if(item.type == FilteredItem::InvalidItem) {
// If there are no error indicators in the line
// maybe this is a multiline case
if(isMultiLineCase(curErrFilter)) {
item.type = FilteredItem::ErrorItem;
} else {
// Okay so we couldn't find anything to indicate an error, but we have file and lineGroup
// Lets keep this item clickable and indicate this to the user.
item.type = FilteredItem::InformationItem;
}
}
}
break;
}
}
return item;
}
/// --- Script error filter strategy ---
ScriptErrorFilterStrategy::ScriptErrorFilterStrategy()
{
}
FilteredItem ScriptErrorFilterStrategy::actionInLine(const QString& line)
{
return FilteredItem(line);
}
FilteredItem ScriptErrorFilterStrategy::errorInLine(const QString& line)
{
// A list of filters for possible Python and PHP errors
static const ErrorFormat SCRIPT_ERROR_FILTERS[] = {
ErrorFormat( QStringLiteral("^ File \"(.*)\", line ([0-9]+)(.*$|, in(.*)$)"), 1, 2, -1 ),
ErrorFormat( QStringLiteral("^.*(/.*):([0-9]+).*$"), 1, 2, -1 ),
ErrorFormat( QStringLiteral("^.* in (/.*) on line ([0-9]+).*$"), 1, 2, -1 )
};
return match(SCRIPT_ERROR_FILTERS, line);
}
/// --- Native application error filter strategy ---
NativeAppErrorFilterStrategy::NativeAppErrorFilterStrategy()
{
}
FilteredItem NativeAppErrorFilterStrategy::actionInLine(const QString& line)
{
return FilteredItem(line);
}
FilteredItem NativeAppErrorFilterStrategy::errorInLine(const QString& line)
{
- static const ErrorFormat QT_APPLICATION_ERROR_FILTERS[] = {
+ static const ErrorFormat NATIVE_APPLICATION_ERROR_FILTERS[] = {
+ // BEGIN: C++
+
+ // a.out: test.cpp:5: int main(): Assertion `false' failed.
+ ErrorFormat(QStringLiteral("^.+: (.+):([1-9][0-9]*): .*: Assertion `.*' failed\\.$"), 1, 2, -1),
+
+ // END: C++
+
+ // BEGIN: Qt
+
+ // Note: Scan the whole line for catching Qt runtime warnings (-> no ^$)
+ // Reasoning: With QT_MESSAGE_PATTERN you can configure the output to your desire,
+ // which means the output could be arbitrarily prefixed or suffixed with other content
+
// QObject::connect related errors, also see err_method_notfound() in qobject.cpp
// QObject::connect: No such slot Foo::bar() in /foo/bar.cpp:313
- ErrorFormat(QStringLiteral("^QObject::connect: (?:No such|Parentheses expected,) (?:slot|signal) [^ ]* in (.*):([0-9]+)$"), 1, 2, -1),
+ ErrorFormat(QStringLiteral("QObject::connect: (?:No such|Parentheses expected,) (?:slot|signal) [^ ]* in (.*):([0-9]+)"), 1, 2, -1),
// ASSERT: "errors().isEmpty()" in file /foo/bar.cpp, line 49
- ErrorFormat(QStringLiteral("^ASSERT: \"(.*)\" in file (.*), line ([0-9]+)$"), 2, 3, -1),
- // QFATAL : FooTest::testBar() ASSERT: "index.isValid()" in file /foo/bar.cpp, line 32
- ErrorFormat(QStringLiteral("^QFATAL : (.*) ASSERT: \"(.*)\" in file (.*), line ([0-9]+)$"), 3, 4, -1),
+ ErrorFormat(QStringLiteral("ASSERT: \"(.*)\" in file (.*), line ([0-9]+)"), 2, 3, -1),
// Catch:
// FAIL! : FooTest::testBar() Compared pointers are not the same
// Actual ...
// Expected ...
// Loc: [/foo/bar.cpp(33)]
//
// Do *not* catch:
// ...
// Loc: [Unknown file(0)]
- ErrorFormat(QStringLiteral("^ Loc: \\[(.*)\\(([1-9][0-9]*)\\)\\]$"), 1, 2, -1)
+ ErrorFormat(QStringLiteral(" Loc: \\[(.*)\\(([1-9][0-9]*)\\)\\]"), 1, 2, -1),
+ // file:///path/to/foo.qml:7:1: Bar is not a type
+ ErrorFormat(QStringLiteral("(file:\\/\\/(?:.+)):([1-9][0-9]*):([1-9][0-9]*): (.+) (?:is not a type|is ambiguous\\.|is instantiated recursively)"), 1, 2, -1, 3)
+
+ // END: Qt
};
- return match(QT_APPLICATION_ERROR_FILTERS, line);
+ return match(NATIVE_APPLICATION_ERROR_FILTERS, line);
}
/// --- Static Analysis filter strategy ---
StaticAnalysisFilterStrategy::StaticAnalysisFilterStrategy()
{
}
FilteredItem StaticAnalysisFilterStrategy::actionInLine(const QString& line)
{
return FilteredItem(line);
}
FilteredItem StaticAnalysisFilterStrategy::errorInLine(const QString& line)
{
// A list of filters for static analysis tools (krazy2, cppcheck)
static const ErrorFormat STATIC_ANALYSIS_FILTERS[] = {
// CppCheck
ErrorFormat( QStringLiteral("^\\[(.*):([0-9]+)\\]:(.*)"), 1, 2, 3 ),
// krazy2
ErrorFormat( QStringLiteral("^\\t([^:]+).*line#([0-9]+).*"), 1, 2, -1 ),
// krazy2 without line info
ErrorFormat( QStringLiteral("^\\t(.*): missing license"), 1, -1, -1 )
};
return match(STATIC_ANALYSIS_FILTERS, line);
}
diff --git a/outputview/tests/test_filteringstrategy.cpp b/outputview/tests/test_filteringstrategy.cpp
index b4e1552d94..9d02aba50b 100644
--- a/outputview/tests/test_filteringstrategy.cpp
+++ b/outputview/tests/test_filteringstrategy.cpp
@@ -1,486 +1,507 @@
/*
This file is part of KDevelop
Copyright 2012 Milian Wolff
Copyright (C) 2012 Morten Danielsen Volden mvolden2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "test_filteringstrategy.h"
#include "testlinebuilderfunctions.h"
#include
#include
#include
using namespace KDevelop;
QTEST_GUILESS_MAIN(TestFilteringStrategy)
namespace QTest {
template<>
inline char* toString(const FilteredItem::FilteredOutputItemType& type)
{
switch (type) {
case FilteredItem::ActionItem:
return qstrdup("ActionItem");
case FilteredItem::CustomItem:
return qstrdup("CustomItem");
case FilteredItem::ErrorItem:
return qstrdup("ErrorItem");
case FilteredItem::InformationItem:
return qstrdup("InformationItem");
case FilteredItem::InvalidItem:
return qstrdup("InvalidItem");
case FilteredItem::StandardItem:
return qstrdup("StandardItem");
case FilteredItem::WarningItem:
return qstrdup("WarningItem");
}
return qstrdup("unknown");
}
}
void TestFilteringStrategy::testNoFilterStrategy_data()
{
QTest::addColumn("line");
QTest::addColumn("expected");
QTest::newRow("cppcheck-info-line")
<< buildCppCheckInformationLine() << FilteredItem::InvalidItem;
QTest::newRow("cppcheck-error-line")
<< buildCppCheckErrorLine() << FilteredItem::InvalidItem;
QTest::newRow("compiler-line")
<< buildCompilerLine() << FilteredItem::InvalidItem;
QTest::newRow("compiler-error-line")
<< buildCompilerErrorLine() << FilteredItem::InvalidItem;
QTest::newRow("compiler-action-line")
<< buildCompilerActionLine() << FilteredItem::InvalidItem;
QTest::newRow("compiler-information-line")
<< buildCompilerInformationLine() << FilteredItem::InvalidItem;
QTest::newRow("python-error-line")
<< buildPythonErrorLine() << FilteredItem::InvalidItem;
}
void TestFilteringStrategy::testNoFilterStrategy()
{
QFETCH(QString, line);
QFETCH(FilteredItem::FilteredOutputItemType, expected);
NoFilterStrategy testee;
FilteredItem item1 = testee.errorInLine(line);
QCOMPARE(item1.type, expected);
item1 = testee.actionInLine(line);
QCOMPARE(item1.type, expected);
}
void TestFilteringStrategy::testCompilerFilterStrategy_data()
{
QTest::addColumn("line");
QTest::addColumn("expectedError");
QTest::addColumn("expectedAction");
QTest::newRow("cppcheck-info-line")
<< buildCppCheckInformationLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("cppcheck-error-line")
<< buildCppCheckErrorLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-line")
<< buildCompilerLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-error-line")
<< buildCompilerErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-information-line")
<< buildCompilerInformationLine() << FilteredItem::InformationItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-information-line2")
<< buildInfileIncludedFromFirstLine() << FilteredItem::InformationItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-information-line3")
<< buildInfileIncludedFromSecondLine() << FilteredItem::InformationItem << FilteredItem::InvalidItem;
QTest::newRow("cmake-error-line1")
<< "CMake Error at CMakeLists.txt:2 (cmake_minimum_required):" << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("cmake-error-multiline1")
<< "CMake Error: Error in cmake code at" << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("cmake-error-multiline2")
<< buildCmakeConfigureMultiLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("cmake-warning-line")
<< "CMake Warning (dev) in CMakeLists.txt:" << FilteredItem::WarningItem << FilteredItem::InvalidItem;
QTest::newRow("cmake-automoc-error")
<< "AUTOMOC: error: /foo/bar.cpp The file includes the moc file \"moc_bar1.cpp\"" << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("cmake-automoc4-error")
<< "automoc4: The file \"/foo/bar.cpp\" includes the moc file \"bar1.moc\"" << FilteredItem::InformationItem << FilteredItem::InvalidItem;
QTest::newRow("cmake-autogen-error")
<< "AUTOGEN: error: /foo/bar.cpp The file includes the moc file \"moc_bar1.cpp\"" << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("linker-action-line")
<< "linking testCustombuild (g++)" << FilteredItem::InvalidItem << FilteredItem::ActionItem;
QTest::newRow("linker-error-line")
<< buildLinkerErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("python-error-line")
<< buildPythonErrorLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
}
void TestFilteringStrategy::testCompilerFilterStrategy()
{
QFETCH(QString, line);
QFETCH(FilteredItem::FilteredOutputItemType, expectedError);
QFETCH(FilteredItem::FilteredOutputItemType, expectedAction);
QUrl projecturl = QUrl::fromLocalFile( projectPath() );
CompilerFilterStrategy testee(projecturl);
FilteredItem item1 = testee.errorInLine(line);
QCOMPARE(item1.type, expectedError);
item1 = testee.actionInLine(line);
QCOMPARE(item1.type, expectedAction);
}
void TestFilteringStrategy::testCompilerFilterstrategyMultipleKeywords_data()
{
QTest::addColumn("line");
QTest::addColumn("expectedError");
QTest::addColumn("expectedAction");
QTest::newRow("warning-containing-error-word")
<< "RingBuffer.cpp:64:6: warning: unused parameter ‘errorItem’ [-Wunused-parameter]"
<< FilteredItem::WarningItem << FilteredItem::InvalidItem;
QTest::newRow("error-containing-info-word")
<< "NodeSet.hpp:89:27: error: ‘Info’ was not declared in this scope"
<< FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("warning-in-filename-containing-error-word")
<< "ErrorHandling.cpp:100:56: warning: unused parameter ‘item’ [-Wunused-parameter]"
<< FilteredItem::WarningItem << FilteredItem::InvalidItem;
QTest::newRow("error-in-filename-containing-warning-word")
<< "WarningHandling.cpp:100:56: error: ‘Item’ was not declared in this scope"
<< FilteredItem::ErrorItem << FilteredItem::InvalidItem;
}
void TestFilteringStrategy::testCompilerFilterstrategyMultipleKeywords()
{
QFETCH(QString, line);
QFETCH(FilteredItem::FilteredOutputItemType, expectedError);
QFETCH(FilteredItem::FilteredOutputItemType, expectedAction);
QUrl projecturl = QUrl::fromLocalFile( projectPath() );
CompilerFilterStrategy testee(projecturl);
FilteredItem item1 = testee.errorInLine(line);
QCOMPARE(item1.type, expectedError);
item1 = testee.actionInLine(line);
QCOMPARE(item1.type, expectedAction);
}
void TestFilteringStrategy::testCompilerFilterStrategyShortenedText_data()
{
QTest::addColumn("line");
QTest::addColumn("expectedShortenedText");
QTest::newRow("c++-compile")
<< "g++ -c main.cpp -o main.o" << "compiling main.cpp (g++)";
QTest::newRow("clang++-link")
<< "clang++ -c main.cpp -o main.o" << "compiling main.cpp (clang++)";
// see bug: https://bugs.kde.org/show_bug.cgi?id=240017
QTest::newRow("mpicc-link")
<< "/usr/bin/mpicc -c main.cpp -o main.o" << "compiling main.cpp (mpicc)";
QTest::newRow("c++-link")
<< "/usr/bin/g++ main.cpp -o main" << "linking main (g++)";
QTest::newRow("clang++-link")
<< "/usr/bin/clang++ main.cpp -o a.out" << "linking a.out (clang++)";
QTest::newRow("mpicc-link")
<< "mpicc main.cpp -o main" << "linking main (mpicc)";
}
void TestFilteringStrategy::testCompilerFilterStrategyShortenedText()
{
QFETCH(QString, line);
QFETCH(QString, expectedShortenedText);
QUrl projecturl = QUrl::fromLocalFile( projectPath() );
CompilerFilterStrategy testee(projecturl);
FilteredItem item = testee.actionInLine(line);
QCOMPARE(item.shortenedText, expectedShortenedText);
}
void TestFilteringStrategy::testScriptErrorFilterStrategy_data()
{
QTest::addColumn("line");
QTest::addColumn("expectedError");
QTest::addColumn("expectedAction");
QTest::newRow("cppcheck-info-line")
<< buildCppCheckInformationLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("cppcheck-error-line")
<< buildCppCheckErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-line")
<< buildCompilerLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-error-line")
<< buildCompilerErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-action-line")
<< "linking testCustombuild (g++)" << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("python-error-line")
<< buildPythonErrorLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
}
void TestFilteringStrategy::testScriptErrorFilterStrategy()
{
QFETCH(QString, line);
QFETCH(FilteredItem::FilteredOutputItemType, expectedError);
QFETCH(FilteredItem::FilteredOutputItemType, expectedAction);
ScriptErrorFilterStrategy testee;
FilteredItem item1 = testee.errorInLine(line);
QCOMPARE(item1.type, expectedError);
item1 = testee.actionInLine(line);
QCOMPARE(item1.type, expectedAction);
}
void TestFilteringStrategy::testNativeAppErrorFilterStrategy_data()
{
QTest::addColumn("line");
QTest::addColumn("file");
QTest::addColumn("lineNo");
QTest::addColumn("column");
QTest::addColumn("itemtype");
+ // BEGIN: C++
+ QTest::newRow("cassert")
+ << "a.out: /foo/bar/test.cpp:5: int main(): Assertion `false' failed."
+ << "/foo/bar/test.cpp"
+ << 4 << 0 << FilteredItem::ErrorItem;
+ // END: C++
+
+ // BEGIN: Qt
// TODO: qt-connect-* and friends shouldn't be error items but warnings items instead
// this needs refactoring in outputfilteringstrategies, though...
QTest::newRow("qt-connect-nosuch-slot")
<< "QObject::connect: No such slot Foo::bar() in /foo/bar.cpp:313"
<< "/foo/bar.cpp"
<< 312 << 0 << FilteredItem::ErrorItem;
QTest::newRow("qt-connect-nosuch-signal")
<< "QObject::connect: No such signal Foo::bar() in /foo/bar.cpp:313"
<< "/foo/bar.cpp"
<< 312 << 0 << FilteredItem::ErrorItem;
QTest::newRow("qt-connect-parentheses-slot")
<< "QObject::connect: Parentheses expected, slot Foo::bar() in /foo/bar.cpp:313"
<< "/foo/bar.cpp"
<< 312 << 0 << FilteredItem::ErrorItem;
QTest::newRow("qt-connect-parentheses-signal")
<< "QObject::connect: Parentheses expected, signal Foo::bar() in /foo/bar.cpp:313"
<< "/foo/bar.cpp"
<< 312 << 0 << FilteredItem::ErrorItem;
QTest::newRow("qt-assert")
<< "ASSERT: \"errors().isEmpty()\" in file /tmp/foo/bar.cpp, line 49"
<< "/tmp/foo/bar.cpp"
<< 48 << 0 << FilteredItem::ErrorItem;
QTest::newRow("qttest-assert")
<< "QFATAL : FooTest::testBar() ASSERT: \"index.isValid()\" in file /foo/bar.cpp, line 32"
<< "/foo/bar.cpp"
<< 31 << 0 << FilteredItem::ErrorItem;
QTest::newRow("qttest-loc")
<< " Loc: [/foo/bar.cpp(33)]"
<< "/foo/bar.cpp"
<< 32 << 0 << FilteredItem::ErrorItem;
QTest::newRow("qttest-loc-nocatch")
<< " Loc: [Unknown file(0)]"
<< ""
<< -1 << -1 << FilteredItem::InvalidItem;
+ QTest::newRow("qml-import-unix")
+ << "file:///path/to/foo.qml:7:1: Bar is not a type"
+ << "/path/to/foo.qml"
+ << 6 << 0 << FilteredItem::ErrorItem;
+ QTest::newRow("qml-import-unix1")
+ << "file:///path/to/foo.qml:7:1: Bar is ambiguous. Found in A and in B"
+ << "/path/to/foo.qml"
+ << 6 << 0 << FilteredItem::ErrorItem;
+ QTest::newRow("qml-import-unix2")
+ << "file:///path/to/foo.qml:7:1: Bar is instantiated recursively"
+ << "/path/to/foo.qml"
+ << 6 << 0 << FilteredItem::ErrorItem;
+ // END: Qt
}
void TestFilteringStrategy::testNativeAppErrorFilterStrategy()
{
QFETCH(QString, line);
QFETCH(QString, file);
QFETCH(int, lineNo);
QFETCH(int, column);
QFETCH(FilteredItem::FilteredOutputItemType, itemtype);
NativeAppErrorFilterStrategy testee;
FilteredItem item = testee.errorInLine(line);
QCOMPARE(item.url.path(), file);
QCOMPARE(item.lineNo , lineNo);
QCOMPARE(item.columnNo , column);
QCOMPARE(item.type , itemtype);
}
void TestFilteringStrategy::testStaticAnalysisFilterStrategy_data()
{
QTest::addColumn("line");
QTest::addColumn("expectedError");
QTest::addColumn("expectedAction");
QTest::newRow("cppcheck-info-line")
<< buildCppCheckInformationLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("cppcheck-error-line")
<< buildCppCheckErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("krazy2-error-line")
<< buildKrazyErrorLine() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("krazy2-error-line-two-colons")
<< buildKrazyErrorLine2() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("krazy2-error-line-error-description")
<< buildKrazyErrorLine3() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("krazy2-error-line-wo-line-info")
<< buildKrazyErrorLineNoLineInfo() << FilteredItem::ErrorItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-line")
<< buildCompilerLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-error-line")
<< buildCompilerErrorLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("compiler-action-line")
<< "linking testCustombuild (g++)" << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
QTest::newRow("python-error-line")
<< buildPythonErrorLine() << FilteredItem::InvalidItem << FilteredItem::InvalidItem;
}
void TestFilteringStrategy::testStaticAnalysisFilterStrategy()
{
// Test that url's are extracted correctly as well
QString referencePath = projectPath() + "main.cpp";
QFETCH(QString, line);
QFETCH(FilteredItem::FilteredOutputItemType, expectedError);
QFETCH(FilteredItem::FilteredOutputItemType, expectedAction);
StaticAnalysisFilterStrategy testee;
FilteredItem item1 = testee.errorInLine(line);
QString extractedPath = item1.url.toLocalFile();
QVERIFY((item1.type != FilteredItem::ErrorItem) || ( extractedPath == referencePath));
QCOMPARE(item1.type, expectedError);
item1 = testee.actionInLine(line);
QCOMPARE(item1.type, expectedAction);
}
void TestFilteringStrategy::testCompilerFilterstrategyUrlFromAction_data()
{
QTest::addColumn("line");
QTest::addColumn("expectedLastDir");
QString basepath = projectPath();
QTest::newRow("cmake-line1")
<< "[ 25%] Building CXX object path/to/one/CMakeFiles/file.o" << QString( basepath + "/path/to/one" );
QTest::newRow("cmake-line2")
<< "[ 26%] Building CXX object path/to/two/CMakeFiles/file.o" << QString( basepath + "/path/to/two");
QTest::newRow("cmake-line3")
<< "[ 26%] Building CXX object path/to/three/CMakeFiles/file.o" << QString( basepath + "/path/to/three");
QTest::newRow("cmake-line4")
<< "[ 26%] Building CXX object path/to/four/CMakeFiles/file.o" << QString( basepath + "/path/to/four");
QTest::newRow("cmake-line5")
<< "[ 26%] Building CXX object path/to/two/CMakeFiles/file.o" << QString( basepath + "/path/to/two");
QTest::newRow("cd-line6")
<< QString("make[4]: Entering directory '" + basepath + "/path/to/one/'") << QString( basepath + "/path/to/one");
QTest::newRow("waf-cd")
<< QString("Waf: Entering directory `" + basepath + "/path/to/two/'") << QString( basepath + "/path/to/two");
QTest::newRow("cmake-line7")
<< QStringLiteral("[ 50%] Building CXX object CMakeFiles/testdeque.dir/RingBuffer.cpp.o") << QString( basepath);
}
void TestFilteringStrategy::testCompilerFilterstrategyUrlFromAction()
{
QFETCH(QString, line);
QFETCH(QString, expectedLastDir);
QUrl projecturl = QUrl::fromLocalFile( projectPath() );
static CompilerFilterStrategy testee(projecturl);
FilteredItem item1 = testee.actionInLine(line);
QCOMPARE(testee.getCurrentDirs().last(), expectedLastDir);
}
void TestFilteringStrategy::benchMarkCompilerFilterAction()
{
QString projecturl = projectPath();
QStringList outputlines;
const int numLines(10000);
int j(0), k(0), l(0), m(0);
do {
++j; ++k; ++l;
QString tmp;
if(m % 2 == 0) {
tmp = QStringLiteral( "[ 26%] Building CXX object /this/is/the/path/to/the/files/%1/%2/%3/CMakeFiles/file.o").arg( j ).arg( k ).arg( l );
} else {
tmp = QString( "make[4]: Entering directory '" + projecturl + "/this/is/the/path/to/the/files/%1/%2/%3/").arg( j ).arg( k ).arg( l );
}
outputlines << tmp;
if(j % 6 == 0) {
j = 0; ++m;
}
if(k % 9 == 0) {
k = 0; ++m;
}
if(l % 13 == 0) {
l = 0; ++m;
}
}
while(outputlines.size() < numLines ); // gives us numLines (-ish)
QElapsedTimer totalTime;
totalTime.start();
static CompilerFilterStrategy testee(QUrl::fromLocalFile(projecturl));
FilteredItem item1("dummyline", FilteredItem::InvalidItem);
QBENCHMARK {
for(int i = 0; i < outputlines.size(); ++i) {
item1 = testee.actionInLine(outputlines.at(i));
}
}
const qint64 elapsed = totalTime.elapsed();
qDebug() << "ms elapsed to add directories: " << elapsed;
qDebug() << "total number of directories: " << outputlines.count();
const double avgDirectoryInsertion = double(elapsed) / outputlines.count();
qDebug() << "average ms spend pr. dir: " << avgDirectoryInsertion;
QVERIFY(avgDirectoryInsertion < 2);
}
void TestFilteringStrategy::testExtractionOfLineAndColumn_data()
{
QTest::addColumn("line");
QTest::addColumn("file");
QTest::addColumn("lineNr");
QTest::addColumn("column");
QTest::addColumn("itemtype");
#ifdef Q_OS_WIN
QTest::newRow("msvc-compiler-error-line")
<< "Z:\\kderoot\\download\\git\\kcoreaddons\\src\\lib\\jobs\\kjob.cpp(3): error C2065: 'dadsads': undeclared identifier"
<< "Z:/kderoot/download/git/kcoreaddons/src/lib/jobs/kjob.cpp" << 2 << 0 << FilteredItem::ErrorItem;
QTest::newRow("msvc-compiler-warning-line")
<< "c:\\program files\\microsoft visual studio 10.0\\vc\\include\\crtdefs.h(527): warning C4229: anachronism used : modifiers on data are ignored"
<< "c:/program files/microsoft visual studio 10.0/vc/include/crtdefs.h" << 526 << 0 << FilteredItem::WarningItem;
#else
QTest::newRow("gcc-with-col")
<< "/path/to/file.cpp:123:45: fatal error: ..."
<< "/path/to/file.cpp" << 122 << 44 << FilteredItem::ErrorItem;
QTest::newRow("gcc-no-col")
<< "/path/to/file.cpp:123: error ..."
<< "/path/to/file.cpp" << 122 << 0 << FilteredItem::ErrorItem;
QTest::newRow("fortcom")
<< "fortcom: Error: Ogive8.f90, line 123: ..."
<< QString(projectPath() + "/Ogive8.f90") << 122 << 0 << FilteredItem::ErrorItem;
QTest::newRow("fortcomError")
<< "fortcom: Error: ./Ogive8.f90, line 123: ..."
<< QString(projectPath() + "/Ogive8.f90") << 122 << 0 << FilteredItem::ErrorItem;
QTest::newRow("fortcomWarning")
<< "fortcom: Warning: /path/Ogive8.f90, line 123: ..."
<< "/path/Ogive8.f90" << 122 << 0 << FilteredItem::WarningItem;
QTest::newRow("fortcomInfo")
<< "fortcom: Info: Ogive8.f90, line 123: ..."
<< QString(projectPath() + "/Ogive8.f90") << 122 << 0 << FilteredItem::InformationItem;
QTest::newRow("libtool")
<< "libtool: link: warning: ..."
<< "" << -1 << 0 << FilteredItem::WarningItem;
QTest::newRow("gfortranError1")
<< "/path/to/file.f90:123.456:Error: ...."
<< "/path/to/file.f90" << 122 << 455 << FilteredItem::ErrorItem;
QTest::newRow("gfortranError2")
<< "/path/flib.f90:3567.22:"
<< "/path/flib.f90" << 3566 << 21 << FilteredItem::ErrorItem;
#endif
}
void TestFilteringStrategy::testExtractionOfLineAndColumn()
{
QFETCH(QString, line);
QFETCH(QString, file);
QFETCH(int, lineNr);
QFETCH(int, column);
QFETCH(FilteredItem::FilteredOutputItemType, itemtype);
QUrl projecturl = QUrl::fromLocalFile( projectPath() );
CompilerFilterStrategy testee(projecturl);
FilteredItem item1 = testee.errorInLine(line);
QCOMPARE(item1.type , itemtype);
QCOMPARE(KDevelop::toUrlOrLocalFile(item1.url), file);
QCOMPARE(item1.lineNo , lineNr);
QCOMPARE(item1.columnNo , column);
}
diff --git a/shell/areadisplay.cpp b/shell/areadisplay.cpp
index 7699c3228a..8294ce4a27 100644
--- a/shell/areadisplay.cpp
+++ b/shell/areadisplay.cpp
@@ -1,125 +1,125 @@
/***************************************************************************
* Copyright 2013 Aleix Pol Gonzalez *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "areadisplay.h"
#include "mainwindow.h"
#include "workingsetcontroller.h"
#include "core.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace KDevelop;
AreaDisplay::AreaDisplay(KDevelop::MainWindow* parent)
: QWidget(parent)
, m_mainWindow(parent)
{
setLayout(new QHBoxLayout);
- m_separator = new QLabel("|", this);
+ m_separator = new QLabel(QStringLiteral("|"), this);
m_separator->setEnabled(false);
m_separator->setVisible(false);
layout()->addWidget(m_separator);
layout()->setContentsMargins(0, 0, 0, 0);
layout()->addWidget(Core::self()->workingSetControllerInternal()->createSetManagerWidget(m_mainWindow));
m_button = new QToolButton(this);
m_button->setToolTip(i18n(
"Execute actions to change the area.
"
"An area is a toolview configuration for a specific use case. "
"From here you can also navigate back to the default code area."));
m_button->setAutoRaise(true);
m_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
m_button->setPopupMode(QToolButton::InstantPopup);
layout()->addWidget(m_button);
connect(parent, &MainWindow::areaChanged, this, &AreaDisplay::newArea);
}
void AreaDisplay::newArea(Sublime::Area* area)
{
if(m_button->menu())
m_button->menu()->deleteLater();
Sublime::Area* currentArea = m_mainWindow->area();
m_button->setText(currentArea->title());
m_button->setIcon(QIcon::fromTheme(currentArea->iconName()));
QMenu* m = new QMenu(m_button);
m->addActions(area->actions());
- if(currentArea->objectName() != "code") {
+ if(currentArea->objectName() != QStringLiteral("code")) {
if(!m->actions().isEmpty())
m->addSeparator();
- m->addAction(QIcon::fromTheme("document-edit"), i18n("Back to code"), this, SLOT(backToCode()), QKeySequence(Qt::AltModifier | Qt::Key_Backspace));
+ m->addAction(QIcon::fromTheme(QStringLiteral("document-edit")), i18n("Back to code"), this, SLOT(backToCode()), QKeySequence(Qt::AltModifier | Qt::Key_Backspace));
}
m_button->setMenu(m);
//remove the additional widgets we might have added for the last area
QBoxLayout* l = qobject_cast(layout());
if(l->count()>=4) {
QLayoutItem* item = l->takeAt(0);
delete item->widget();
delete item;
}
QWidget* w = Core::self()->workingSetControllerInternal()->createSetManagerWidget(m_mainWindow, area);
w->installEventFilter(this);
m_separator->setVisible(w->isVisible());
l->insertWidget(0, w);
}
bool AreaDisplay::eventFilter(QObject* obj, QEvent* event)
{
if (event->type() == QEvent::Show) {
m_separator->setVisible(true);
} else if (event->type() == QEvent::Hide) {
m_separator->setVisible(false);
}
return QObject::eventFilter(obj, event);
}
void AreaDisplay::backToCode()
{
- ICore::self()->uiController()->switchToArea("code", IUiController::ThisWindow);
+ ICore::self()->uiController()->switchToArea(QStringLiteral("code"), IUiController::ThisWindow);
}
QSize AreaDisplay::minimumSizeHint() const
{
QSize hint = QWidget::minimumSizeHint();
hint = hint.boundedTo(QSize(hint.width(), m_mainWindow->menuBar()->height()-1));
return hint;
}
QSize AreaDisplay::sizeHint() const
{
QSize hint = QWidget::sizeHint();
hint = hint.boundedTo(QSize(hint.width(), m_mainWindow->menuBar()->height()-1));
return hint;
}
diff --git a/shell/completionsettings.cpp b/shell/completionsettings.cpp
index 89cf68b46e..121adec707 100644
--- a/shell/completionsettings.cpp
+++ b/shell/completionsettings.cpp
@@ -1,108 +1,108 @@
/***************************************************************************
* Copyright 2008 David Nolden *
* Copyright 2013 Vlas Puhov *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "completionsettings.h"
#include
namespace KDevelop
{
static QString completionLevelToString(ICompletionSettings::CompletionLevel l)
{
if (l < 0 || l >= ICompletionSettings::LAST_LEVEL) {
return QString();
}
- const static QString levels[ICompletionSettings::LAST_LEVEL] = {"Minimal", "MinimalWhenAutomatic", "AlwaysFull"};
+ const static QString levels[ICompletionSettings::LAST_LEVEL] = {QStringLiteral("Minimal"), QStringLiteral("MinimalWhenAutomatic"), QStringLiteral("AlwaysFull")};
return levels[l];
}
CompletionSettings& CompletionSettings::self()
{
static CompletionSettings settings;
return settings;
}
QStringList CompletionSettings::todoMarkerWords() const
{
const QString markers = m_languageGroup.readEntry("todoMarkerWords", m_todoMarkerWords);
return KShell::splitArgs(markers);
}
int CompletionSettings::minFilesForSimplifiedParsing() const
{
return m_languageGroup.readEntry("minFilesForSimplifiedParsing", m_minFilesForSimplifiedParsing);
}
bool CompletionSettings::showMultiLineSelectionInformation() const
{
return m_languageGroup.readEntry("showMultiLineSelectionInformation", m_showMultiLineInformation);
}
bool CompletionSettings::highlightProblematicLines() const
{
return m_languageGroup.readEntry("highlightProblematicLines", m_highlightProblematicLines);
}
bool CompletionSettings::highlightSemanticProblems() const
{
return m_languageGroup.readEntry("highlightSemanticProblems", m_highlightSemanticProblems);
}
bool CompletionSettings::boldDeclarations() const
{
return m_languageGroup.readEntry("boldDeclarations", m_boldDeclarations);
}
int CompletionSettings::globalColorizationLevel() const
{
return m_languageGroup.readEntry("globalColorization", m_globalColorizationLevel);
}
int CompletionSettings::localColorizationLevel() const
{
return m_languageGroup.readEntry("localColorization", m_localColorizationLevel);
}
bool CompletionSettings::automaticCompletionEnabled() const
{
return m_languageGroup.readEntry("Automatic Invocation", m_automatic);
}
ICompletionSettings::CompletionLevel CompletionSettings::completionLevel() const
{
const QString level = m_languageGroup.readEntry("completionDetail", completionLevelToString(m_level));
for (int i = 0; i < ICompletionSettings::LAST_LEVEL; i++) {
if (completionLevelToString(static_cast(i)) == level) {
return static_cast(i);
}
}
return m_level;
}
CompletionSettings::CompletionSettings()
: m_level(MinimalWhenAutomatic), m_automatic(true),
m_highlightSemanticProblems(true), m_highlightProblematicLines(false), m_showMultiLineInformation(false),
m_boldDeclarations(true), m_localColorizationLevel(170), m_globalColorizationLevel(255),
- m_minFilesForSimplifiedParsing(100000), m_todoMarkerWords("TODO FIXME"),
+ m_minFilesForSimplifiedParsing(100000), m_todoMarkerWords(QStringLiteral("TODO FIXME")),
m_languageGroup(KSharedConfig::openConfig(), "Language Support"){}
}
diff --git a/shell/completionsettings.h b/shell/completionsettings.h
index 05f166b432..31ac38167a 100644
--- a/shell/completionsettings.h
+++ b/shell/completionsettings.h
@@ -1,74 +1,75 @@
/***************************************************************************
* Copyright 2008 David Nolden *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef KDEVPLATFORM_COMPLETIONSETTINGS_H
#define KDEVPLATFORM_COMPLETIONSETTINGS_H
#include
#include
#include
namespace KDevelop
{
class CompletionSettings : public KDevelop::ICompletionSettings
{
+ Q_OBJECT
public:
virtual CompletionLevel completionLevel() const override;
virtual bool automaticCompletionEnabled() const override;
void emitChanged() { emit settingsChanged(this); }
virtual int localColorizationLevel() const override;
virtual int globalColorizationLevel() const override;
virtual bool highlightSemanticProblems() const override;
virtual bool highlightProblematicLines() const override;
virtual bool boldDeclarations() const override;
virtual bool showMultiLineSelectionInformation() const override;
virtual int minFilesForSimplifiedParsing() const override;
virtual QStringList todoMarkerWords() const override;
static CompletionSettings& self();
private:
CompletionSettings();
const CompletionLevel m_level;
const bool m_automatic;
const bool m_highlightSemanticProblems;
const bool m_highlightProblematicLines;
const bool m_showMultiLineInformation;
const bool m_boldDeclarations;
const int m_localColorizationLevel;
const int m_globalColorizationLevel;
const int m_minFilesForSimplifiedParsing;
const QString m_todoMarkerWords;
const KConfigGroup m_languageGroup;
};
}
#endif
diff --git a/shell/configdialog.cpp b/shell/configdialog.cpp
index cd292efe39..2db2da94cd 100644
--- a/shell/configdialog.cpp
+++ b/shell/configdialog.cpp
@@ -1,219 +1,219 @@
/*
* This file is part of KDevelop
* Copyright 2014 Alex Richardson
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3, or any
* later version accepted by the membership of KDE e.V. (or its
* successor approved by the membership of KDE e.V.), which shall
* act as a proxy defined in Section 6 of version 3 of the license.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*/
#include "configdialog.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace KDevelop;
//FIXME: unit test this code!
ConfigDialog::ConfigDialog(const QVector& pages, QWidget* parent, Qt::WindowFlags flags)
: KPageDialog(parent, flags), m_currentPageHasChanges(false)
{
setWindowTitle(i18n("Configure"));
setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults);
button(QDialogButtonBox::Apply)->setEnabled(false);
setObjectName(QStringLiteral("configdialog"));
for (auto page : pages) {
addConfigPage(page);
}
auto onApplyClicked = [this] {
auto page = qobject_cast(currentPage()->widget());
Q_ASSERT(page);
applyChanges(page);
};
connect(button(QDialogButtonBox::Apply), &QPushButton::clicked, onApplyClicked);
connect(button(QDialogButtonBox::Ok), &QPushButton::clicked, onApplyClicked);
connect(button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, [this]() {
auto page = qobject_cast(currentPage()->widget());
Q_ASSERT(page);
page->defaults();
});
connect(this, &KPageDialog::currentPageChanged, this, &ConfigDialog::checkForUnsavedChanges);
// make sure we don't keep any entries for unloaded plugins
connect(ICore::self()->pluginController(), &IPluginController::unloadingPlugin,
this, &ConfigDialog::removePagesForPlugin);
}
KPageWidgetItem* ConfigDialog::itemForPage(ConfigPage* page) const
{
- for (auto item : m_pages) {
+ for (auto& item : m_pages) {
if (item->widget() == page) {
return item;
}
}
return nullptr;
}
int ConfigDialog::checkForUnsavedChanges(KPageWidgetItem* current, KPageWidgetItem* before)
{
Q_UNUSED(current);
if (!m_currentPageHasChanges) {
return KMessageBox::Yes;
}
// before must be non-null, because if we change from nothing to a new page m_currentPageHasChanges must also be false!
Q_ASSERT(before);
auto oldPage = qobject_cast(before->widget());
Q_ASSERT(oldPage);
auto dialogResult = KMessageBox::warningYesNoCancel(this, i18n("The settings of the current module have changed.\n"
"Do you want to apply the changes or discard them?"), i18n("Apply Settings"), KStandardGuiItem::apply(),
KStandardGuiItem::discard(), KStandardGuiItem::cancel());
if (dialogResult == KMessageBox::No) {
oldPage->reset();
m_currentPageHasChanges = false;
button(QDialogButtonBox::Apply)->setEnabled(false);
} else if (dialogResult == KMessageBox::Yes) {
applyChanges(oldPage);
} else if (dialogResult == KMessageBox::Cancel) {
// restore old state
QSignalBlocker block(this); // prevent recursion
setCurrentPage(before);
}
return dialogResult;
}
void ConfigDialog::closeEvent(QCloseEvent* event)
{
if (checkForUnsavedChanges(currentPage(), currentPage()) == KMessageBox::Cancel) {
// if the user clicked cancel he wants to continue editing the current page -> don't close
event->ignore();
} else {
event->accept();
}
}
void ConfigDialog::removeConfigPage(ConfigPage* page)
{
auto item = itemForPage(page);
Q_ASSERT(item);
removePage(item);
m_pages.removeAll(QPointer(item));
// also remove all items that were deleted because a parent KPageWidgetItem was removed
m_pages.removeAll(QPointer());
}
void ConfigDialog::removePagesForPlugin(IPlugin* plugin)
{
Q_ASSERT(plugin);
- for (auto&& item : m_pages) {
+ foreach (auto&& item, m_pages) {
if (!item) {
continue;
}
auto page = qobject_cast(item->widget());
if (page && page->plugin() == plugin) {
removePage(item); // this also deletes the config page -> QPointer is set to null
}
};
// also remove all items that were deleted because a parent KPageWidgetItem was removed
m_pages.removeAll(QPointer());
}
void ConfigDialog::addConfigPage(ConfigPage* page, ConfigPage* previous)
{
if (previous) {
auto previousItem = itemForPage(previous);
Q_ASSERT(previousItem);
addConfigPageInternal(insertPage(previousItem, page, page->name()), page);
} else {
addConfigPageInternal(addPage(page, page->name()), page);
}
}
void ConfigDialog::addSubConfigPage(ConfigPage* parentPage, ConfigPage* page)
{
auto item = itemForPage(parentPage);
Q_ASSERT(item);
addConfigPageInternal(addSubPage(item, page, page->name()), page);
}
void ConfigDialog::addConfigPageInternal(KPageWidgetItem* item, ConfigPage* page)
{
item->setHeader(page->fullName());
item->setIcon(page->icon());
page->initConfigManager();
page->reset(); // make sure all widgets are in the correct state
// make sure that we only connect to changed after calling reset()
connect(page, &ConfigPage::changed, this, &ConfigDialog::onPageChanged);
m_pages.append(item);
for (int i = 0; i < page->childPages(); ++i) {
auto child = page->childPage(i);
addSubConfigPage(page, child);
}
}
void ConfigDialog::onPageChanged()
{
QObject* from = sender();
if (from && from != currentPage()->widget()) {
qWarning() << "Settings in config page" << from << "changed, while" << currentPage()->widget() << "is currently selected. This case is not implemented yet.";
return;
// TODO: add a QHash as a member to make sure the apply button is always correct
// TODO: when pressing okay show confirm dialog if other pages have changed or just silently apply every page? "Items on other pages have changed, do you wish to review those changes? + list with changed pages."
}
if (!m_currentlyApplyingChanges) {
// e.g. PluginPreferences emits changed() from its apply method, better fix this here than having to
// ensure that no plugin emits changed() from apply()
// together with KPageDialog emitting currentPageChanged("Plugins", nullptr) this could cause a crash
// when we dereference before
m_currentPageHasChanges = true;
button(QDialogButtonBox::Apply)->setEnabled(true);
}
}
void ConfigDialog::applyChanges(ConfigPage* page)
{
// must set this to false before calling apply, otherwise we get the confirmation dialog
// whenever we enable/disable plugins.
// This is because KPageWidget then emits currentPageChanged("Plugins", nullptr), which seems like a bug to me,
// it should rather emit currentPageChanged("Plugins", "Plugins") or even better nothing at all, since the current
// page did not actually change!
// TODO: fix KPageWidget
m_currentPageHasChanges = false;
m_currentlyApplyingChanges = true;
page->apply();
m_currentlyApplyingChanges = false;
Q_ASSERT(!m_currentPageHasChanges);
button(QDialogButtonBox::Apply)->setEnabled(false);
emit configSaved(page);
}
diff --git a/shell/core.cpp b/shell/core.cpp
index 640079c507..6df65f2231 100644
--- a/shell/core.cpp
+++ b/shell/core.cpp
@@ -1,602 +1,602 @@
/***************************************************************************
* Copyright 2007 Alexander Dymo *
* Copyright 2007 Kris Wong *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "core.h"
#include "core_p.h"
#include
#include
#include
#include
#include "mainwindow.h"
#include "sessioncontroller.h"
#include "uicontroller.h"
#include "plugincontroller.h"
#include "projectcontroller.h"
#include "partcontroller.h"
#include "languagecontroller.h"
#include "documentcontroller.h"
#include "runcontroller.h"
#include "session.h"
#include "documentationcontroller.h"
#include "sourceformattercontroller.h"
#include "progresswidget/progressmanager.h"
#include "selectioncontroller.h"
#include "debugcontroller.h"
#include "kdevplatform_version.h"
#include "workingsetcontroller.h"
#include "testcontroller.h"
#include "debug.h"
#include
#include
#include
#include
namespace {
void shutdownGracefully(int sig)
{
static volatile std::sig_atomic_t handlingSignal = 0;
if ( !handlingSignal ) {
handlingSignal = 1;
qCDebug(SHELL) << "signal " << sig << " received, shutting down gracefully";
QCoreApplication* app = QCoreApplication::instance();
if (QApplication* guiApp = qobject_cast(app)) {
guiApp->closeAllWindows();
}
app->quit();
return;
}
// re-raise signal with default handler and trigger program termination
std::signal(sig, SIG_DFL);
std::raise(sig);
}
void installSignalHandler()
{
#ifdef SIGHUP
std::signal(SIGHUP, shutdownGracefully);
#endif
#ifdef SIGINT
std::signal(SIGINT, shutdownGracefully);
#endif
#ifdef SIGTERM
std::signal(SIGTERM, shutdownGracefully);
#endif
}
}
namespace KDevelop {
Core *Core::m_self = 0;
KAboutData createAboutData()
{
- KAboutData aboutData( "kdevplatform",
- i18n("KDevelop Platform"), KDEVPLATFORM_VERSION_STRING,
+ KAboutData aboutData( QStringLiteral("kdevplatform"),
+ i18n("KDevelop Platform"), QStringLiteral(KDEVPLATFORM_VERSION_STRING),
i18n("Development Platform for IDE-like Applications"),
KAboutLicense::LGPL_V2, i18n( "Copyright 2004-2015, The KDevelop developers" ),
- QString(), "http://www.kdevelop.org" );
-
- aboutData.addAuthor( i18n("Andreas Pakulat"), i18n( "Architecture, VCS Support, Project Management Support, QMake Projectmanager" ), "apaku@gmx.de" );
- aboutData.addAuthor( i18n("Alexander Dymo"), i18n( "Architecture, Sublime UI, Ruby support" ), "adymo@kdevelop.org" );
- aboutData.addAuthor( i18n("David Nolden"), i18n( "Definition-Use Chain, C++ Support" ), "david.nolden.kdevelop@art-master.de" );
- aboutData.addAuthor( i18n("Aleix Pol Gonzalez"), i18n( "Co-Maintainer, CMake Support, Run Support, Kross Support" ), "aleixpol@kde.org" );
- aboutData.addAuthor( i18n("Vladimir Prus"), i18n( "GDB integration" ), "ghost@cs.msu.su" );
- aboutData.addAuthor( i18n("Hamish Rodda"), i18n( "Text editor integration, definition-use chain" ), "rodda@kde.org" );
-
- aboutData.addCredit( i18n("Matt Rogers"), QString(), "mattr@kde.org");
- aboutData.addCredit( i18n("Cédric Pasteur"), i18n("astyle and indent support"), "cedric.pasteur@free.fr" );
- aboutData.addCredit( i18n("Evgeniy Ivanov"), i18n("Distributed VCS, Git, Mercurial"), "powerfox@kde.ru" );
+ QString(), QStringLiteral("http://www.kdevelop.org") );
+
+ aboutData.addAuthor( i18n("Andreas Pakulat"), i18n( "Architecture, VCS Support, Project Management Support, QMake Projectmanager" ), QStringLiteral("apaku@gmx.de") );
+ aboutData.addAuthor( i18n("Alexander Dymo"), i18n( "Architecture, Sublime UI, Ruby support" ), QStringLiteral("adymo@kdevelop.org") );
+ aboutData.addAuthor( i18n("David Nolden"), i18n( "Definition-Use Chain, C++ Support" ), QStringLiteral("david.nolden.kdevelop@art-master.de") );
+ aboutData.addAuthor( i18n("Aleix Pol Gonzalez"), i18n( "Co-Maintainer, CMake Support, Run Support, Kross Support" ), QStringLiteral("aleixpol@kde.org") );
+ aboutData.addAuthor( i18n("Vladimir Prus"), i18n( "GDB integration" ), QStringLiteral("ghost@cs.msu.su") );
+ aboutData.addAuthor( i18n("Hamish Rodda"), i18n( "Text editor integration, definition-use chain" ), QStringLiteral("rodda@kde.org") );
+
+ aboutData.addCredit( i18n("Matt Rogers"), QString(), QStringLiteral("mattr@kde.org"));
+ aboutData.addCredit( i18n("Cédric Pasteur"), i18n("astyle and indent support"), QStringLiteral("cedric.pasteur@free.fr") );
+ aboutData.addCredit( i18n("Evgeniy Ivanov"), i18n("Distributed VCS, Git, Mercurial"), QStringLiteral("powerfox@kde.ru") );
//Veritas is outside in playground currently.
//aboutData.addCredit( i18n("Manuel Breugelmanns"), i18n( "Veritas, QTest integraton"), "mbr.nxi@gmail.com" );
- aboutData.addCredit( i18n("Robert Gruber") , i18n( "SnippetPart, debugger and usability patches" ), "rgruber@users.sourceforge.net" );
- aboutData.addCredit( i18n("Dukju Ahn"), i18n( "Subversion plugin, Custom Make Manager, Overall improvements" ), "dukjuahn@gmail.com" );
- aboutData.addAuthor( i18n("Niko Sams"), i18n( "GDB integration, Webdevelopment Plugins" ), "niko.sams@gmail.com" );
- aboutData.addAuthor( i18n("Milian Wolff"), i18n( "Co-Maintainer, Generic manager, Webdevelopment Plugins, Snippets, Performance" ), "mail@milianw.de" );
+ aboutData.addCredit( i18n("Robert Gruber") , i18n( "SnippetPart, debugger and usability patches" ), QStringLiteral("rgruber@users.sourceforge.net") );
+ aboutData.addCredit( i18n("Dukju Ahn"), i18n( "Subversion plugin, Custom Make Manager, Overall improvements" ), QStringLiteral("dukjuahn@gmail.com") );
+ aboutData.addAuthor( i18n("Niko Sams"), i18n( "GDB integration, Webdevelopment Plugins" ), QStringLiteral("niko.sams@gmail.com") );
+ aboutData.addAuthor( i18n("Milian Wolff"), i18n( "Co-Maintainer, Generic manager, Webdevelopment Plugins, Snippets, Performance" ), QStringLiteral("mail@milianw.de") );
return aboutData;
}
CorePrivate::CorePrivate(Core *core):
m_aboutData( createAboutData() ), m_core(core), m_cleanedUp(false), m_shuttingDown(false)
{
}
bool CorePrivate::initialize(Core::Setup mode, QString session )
{
m_mode=mode;
qCDebug(SHELL) << "Creating controllers";
emit m_core->startupProgress(0);
if( !sessionController )
{
sessionController = new SessionController(m_core);
}
if( !workingSetController && !(mode & Core::NoUi) )
{
workingSetController = new WorkingSetController();
}
qCDebug(SHELL) << "Creating ui controller";
if( !uiController )
{
uiController = new UiController(m_core);
}
emit m_core->startupProgress(10);
qCDebug(SHELL) << "Creating plugin controller";
if( !pluginController )
{
pluginController = new PluginController(m_core);
}
if( !partController && !(mode & Core::NoUi))
{
partController = new PartController(m_core, uiController.data()->defaultMainWindow());
}
emit m_core->startupProgress(20);
if( !projectController )
{
projectController = new ProjectController(m_core);
}
if( !documentController )
{
documentController = new DocumentController(m_core);
}
if( !languageController )
{
// Must be initialized after documentController, because the background parser depends
// on the document controller.
languageController = new LanguageController(m_core);
}
emit m_core->startupProgress(25);
if( !runController )
{
runController = new RunController(m_core);
}
if( !sourceFormatterController )
{
sourceFormatterController = new SourceFormatterController(m_core);
}
emit m_core->startupProgress(30);
if ( !progressController)
{
progressController = ProgressManager::instance();
}
if( !selectionController )
{
selectionController = new SelectionController(m_core);
}
emit m_core->startupProgress(35);
if( !documentationController && !(mode & Core::NoUi) )
{
documentationController = new DocumentationController(m_core);
}
if( !debugController )
{
debugController = new DebugController(m_core);
}
emit m_core->startupProgress(40);
if( !testController )
{
testController = new TestController(m_core);
}
emit m_core->startupProgress(47);
qCDebug(SHELL) << "Done creating controllers";
qCDebug(SHELL) << "Initializing controllers";
sessionController.data()->initialize( session );
if( !sessionController.data()->activeSessionLock() ) {
return false;
}
emit m_core->startupProgress(55);
// TODO: Is this early enough, or should we put the loading of the session into
// the controller construct
DUChain::initialize();
if (!(mode & Core::NoUi)) {
uiController.data()->initialize();
}
languageController.data()->initialize();
if (partController) {
partController.data()->initialize();
}
projectController.data()->initialize();
documentController.data()->initialize();
emit m_core->startupProgress(63);
/* This is somewhat messy. We want to load the areas before
loading the plugins, so that when each plugin is loaded we
know if an area wants some of the tool view from that plugin.
OTOH, loading of areas creates documents, and some documents
might require that a plugin is already loaded.
Probably, the best approach would be to plugins to just add
tool views to a list of available tool view, and then grab
those tool views when loading an area. */
qCDebug(SHELL) << "Initializing plugin controller (loading session plugins)";
pluginController.data()->initialize();
emit m_core->startupProgress(78);
qCDebug(SHELL) << "Initializing working set controller";
if(!(mode & Core::NoUi))
{
workingSetController.data()->initialize();
/* Need to do this after everything else is loaded. It's too
hard to restore position of views, and toolbars, and whatever
that are not created yet. */
uiController.data()->loadAllAreas(KSharedConfig::openConfig());
uiController.data()->defaultMainWindow()->show();
}
emit m_core->startupProgress(90);
qCDebug(SHELL) << "Initializing remaining controllers";
runController.data()->initialize();
sourceFormatterController.data()->initialize();
selectionController.data()->initialize();
if (documentationController) {
documentationController.data()->initialize();
}
emit m_core->startupProgress(95);
debugController.data()->initialize();
testController.data()->initialize();
installSignalHandler();
qCDebug(SHELL) << "Done initializing controllers";
if (partController) {
// check features of kate and report to user if it does not fit
KTextEditor::Document* doc = partController.data()->createTextPart();
if ( !qobject_cast< KTextEditor::MovingInterface* >(doc) ) {
KMessageBox::error(QApplication::activeWindow(),
i18n("The installed Kate version does not support the MovingInterface which is crucial for "
"KDevelop starting from version 4.2.\n\n"
"To use KDevelop with KDE SC prior to 4.6, where the SmartInterface is used instead "
"of the MovingInterface, you need KDevelop 4.1 or lower."));
delete doc;
return false;
}
delete doc;
}
emit m_core->startupProgress(100);
return true;
}
CorePrivate::~CorePrivate()
{
delete selectionController.data();
delete projectController.data();
delete languageController.data();
delete pluginController.data();
delete uiController.data();
delete partController.data();
delete documentController.data();
delete runController.data();
delete sessionController.data();
delete sourceFormatterController.data();
delete documentationController.data();
delete debugController.data();
delete workingSetController.data();
delete testController.data();
selectionController.clear();
projectController.clear();
languageController.clear();
pluginController.clear();
uiController.clear();
partController.clear();
documentController.clear();
runController.clear();
sessionController.clear();
sourceFormatterController.clear();
documentationController.clear();
debugController.clear();
workingSetController.clear();
testController.clear();
}
bool Core::initialize(QObject* splash, Setup mode, const QString& session )
{
if (m_self)
return true;
m_self = new Core();
if (splash) {
// can't use new signal/slot syntax here, we don't know the class that splash has at runtime
connect(m_self, SIGNAL(startupProgress(int)), splash, SLOT(progress(int)));
}
bool ret = m_self->d->initialize(mode, session);
if( splash ) {
QTimer::singleShot( 200, splash, SLOT(deleteLater()) );
}
if(ret)
emit m_self->initializationCompleted();
return ret;
}
Core *KDevelop::Core::self()
{
return m_self;
}
Core::Core(QObject *parent)
: ICore(parent)
{
d = new CorePrivate(this);
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &Core::shutdown);
}
Core::Core(CorePrivate* dd, QObject* parent)
: ICore(parent), d(dd)
{
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &Core::shutdown);
}
Core::~Core()
{
qCDebug(SHELL);
//Cleanup already called before mass destruction of GUI
delete d;
m_self = 0;
}
Core::Setup Core::setupFlags() const
{
return d->m_mode;
}
void Core::shutdown()
{
qCDebug(SHELL);
if (!d->m_shuttingDown) {
cleanup();
deleteLater();
}
qCDebug(SHELL) << "Shutdown done";
}
bool Core::shuttingDown() const
{
return d->m_shuttingDown;
}
void Core::cleanup()
{
qCDebug(SHELL);
d->m_shuttingDown = true;
emit aboutToShutdown();
if (!d->m_cleanedUp) {
d->debugController.data()->cleanup();
d->selectionController.data()->cleanup();
// Save the layout of the ui here, so run it first
d->uiController.data()->cleanup();
if (d->workingSetController)
d->workingSetController.data()->cleanup();
/* Must be called before projectController.data()->cleanup(). */
// Closes all documents (discards, as already saved if the user wished earlier)
d->documentController.data()->cleanup();
d->runController.data()->cleanup();
if (d->partController) {
d->partController->cleanup();
}
d->projectController.data()->cleanup();
d->sourceFormatterController.data()->cleanup();
d->pluginController.data()->cleanup();
d->sessionController.data()->cleanup();
d->testController.data()->cleanup();
//Disable the functionality of the language controller
d->languageController.data()->cleanup();
DUChain::self()->shutdown();
}
d->m_cleanedUp = true;
emit shutdownCompleted();
}
KAboutData Core::aboutData() const
{
return d->m_aboutData;
}
IUiController *Core::uiController()
{
return d->uiController.data();
}
ISession* Core::activeSession()
{
return sessionController()->activeSession();
}
ISessionLock::Ptr Core::activeSessionLock()
{
return sessionController()->activeSessionLock();
}
SessionController *Core::sessionController()
{
return d->sessionController.data();
}
UiController *Core::uiControllerInternal()
{
return d->uiController.data();
}
IPluginController *Core::pluginController()
{
return d->pluginController.data();
}
PluginController *Core::pluginControllerInternal()
{
return d->pluginController.data();
}
IProjectController *Core::projectController()
{
return d->projectController.data();
}
ProjectController *Core::projectControllerInternal()
{
return d->projectController.data();
}
IPartController *Core::partController()
{
return d->partController.data();
}
PartController *Core::partControllerInternal()
{
return d->partController.data();
}
ILanguageController *Core::languageController()
{
return d->languageController.data();
}
LanguageController *Core::languageControllerInternal()
{
return d->languageController.data();
}
IDocumentController *Core::documentController()
{
return d->documentController.data();
}
DocumentController *Core::documentControllerInternal()
{
return d->documentController.data();
}
IRunController *Core::runController()
{
return d->runController.data();
}
RunController *Core::runControllerInternal()
{
return d->runController.data();
}
ISourceFormatterController* Core::sourceFormatterController()
{
return d->sourceFormatterController.data();
}
SourceFormatterController* Core::sourceFormatterControllerInternal()
{
return d->sourceFormatterController.data();
}
ProgressManager *Core::progressController()
{
return d->progressController.data();
}
ISelectionController* Core::selectionController()
{
return d->selectionController.data();
}
IDocumentationController* Core::documentationController()
{
return d->documentationController.data();
}
DocumentationController* Core::documentationControllerInternal()
{
return d->documentationController.data();
}
IDebugController* Core::debugController()
{
return d->debugController.data();
}
DebugController* Core::debugControllerInternal()
{
return d->debugController.data();
}
ITestController* Core::testController()
{
return d->testController.data();
}
TestController* Core::testControllerInternal()
{
return d->testController.data();
}
WorkingSetController* Core::workingSetControllerInternal()
{
return d->workingSetController.data();
}
QString Core::version()
{
- return KDEVPLATFORM_VERSION_STRING;
+ return QStringLiteral(KDEVPLATFORM_VERSION_STRING);
}
}
diff --git a/shell/debugcontroller.cpp b/shell/debugcontroller.cpp
index 520a356ffb..5a9e2c5d9f 100644
--- a/shell/debugcontroller.cpp
+++ b/shell/debugcontroller.cpp
@@ -1,534 +1,534 @@
/* This file is part of KDevelop
*
* Copyright 1999-2001 John Birch
* Copyright 2001 by Bernd Gehrmann
* Copyright 2006 Vladimir Prus
* Copyright 2007 Hamish Rodda
* Copyright 2009 Niko Sams
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "debugcontroller.h"
#include
#include
#include
#include
#include
#include
#include "../interfaces/idocument.h"
#include "../interfaces/icore.h"
#include "../interfaces/idocumentcontroller.h"
#include "../interfaces/ipartcontroller.h"
#include "../interfaces/contextmenuextension.h"
#include "../interfaces/context.h"
#include "../language/interfaces/editorcontext.h"
#include "../sublime/view.h"
#include "../sublime/mainwindow.h"
#include "../sublime/area.h"
#include "../debugger/breakpoint/breakpointmodel.h"
#include "../debugger/breakpoint/breakpointwidget.h"
#include "../debugger/variable/variablewidget.h"
#include "../debugger/framestack/framestackmodel.h"
#include "../debugger/framestack/framestackwidget.h"
#include "core.h"
#include "debug.h"
#include "uicontroller.h"
namespace KDevelop {
template
class DebuggerToolFactory : public KDevelop::IToolViewFactory
{
public:
DebuggerToolFactory(DebugController* controller, const QString &id, Qt::DockWidgetArea defaultArea)
: m_controller(controller), m_id(id), m_defaultArea(defaultArea) {}
QWidget* create(QWidget *parent = 0) override
{
return new T(m_controller, parent);
}
QString id() const override
{
return m_id;
}
Qt::DockWidgetArea defaultPosition() override
{
return m_defaultArea;
}
void viewCreated(Sublime::View* view) override
{
if (view->widget()->metaObject()->indexOfSignal("requestRaise()") != -1)
QObject::connect(view->widget(), SIGNAL(requestRaise()), view, SLOT(requestRaise()));
}
/* At present, some debugger widgets (e.g. breakpoint) contain actions so that shortcuts
work, but they don't need any toolbar. So, suppress toolbar action. */
QList toolBarActions( QWidget* viewWidget ) const override
{
Q_UNUSED(viewWidget);
return QList();
}
private:
DebugController* m_controller;
QString m_id;
Qt::DockWidgetArea m_defaultArea;
};
DebugController::DebugController(QObject *parent)
: IDebugController(parent), KXMLGUIClient(),
m_continueDebugger(0), m_stopDebugger(0),
m_interruptDebugger(0), m_runToCursor(0),
m_jumpToCursor(0), m_stepOver(0),
m_stepIntoInstruction(0), m_stepInto(0),
m_stepOverInstruction(0), m_stepOut(0),
m_toggleBreakpoint(0),
m_breakpointModel(new BreakpointModel(this)),
m_variableCollection(new VariableCollection(this)),
m_uiInitialized(false)
{
- setComponentName("kdevdebugger", "kdevdebugger");
- setXMLFile("kdevdebuggershellui.rc");
+ setComponentName(QStringLiteral("kdevdebugger"), QStringLiteral("kdevdebugger"));
+ setXMLFile(QStringLiteral("kdevdebuggershellui.rc"));
}
void DebugController::initialize()
{
m_breakpointModel->load();
}
void DebugController::initializeUi()
{
if (m_uiInitialized) return;
m_uiInitialized = true;
if((Core::self()->setupFlags() & Core::NoUi)) return;
setupActions();
ICore::self()->uiController()->addToolView(
i18n("Frame Stack"),
new DebuggerToolFactory(
- this, "org.kdevelop.debugger.StackView",
+ this, QStringLiteral("org.kdevelop.debugger.StackView"),
Qt::BottomDockWidgetArea));
ICore::self()->uiController()->addToolView(
i18n("Breakpoints"),
new DebuggerToolFactory(
- this, "org.kdevelop.debugger.BreakpointsView",
+ this, QStringLiteral("org.kdevelop.debugger.BreakpointsView"),
Qt::BottomDockWidgetArea));
ICore::self()->uiController()->addToolView(
i18n("Variables"),
new DebuggerToolFactory(
- this, "org.kdevelop.debugger.VariablesView",
+ this, QStringLiteral("org.kdevelop.debugger.VariablesView"),
Qt::LeftDockWidgetArea));
foreach(KParts::Part* p, KDevelop::ICore::self()->partController()->parts())
partAdded(p);
connect(KDevelop::ICore::self()->partController(),
&IPartController::partAdded,
this,
&DebugController::partAdded);
ICore::self()->uiController()->activeMainWindow()->guiFactory()->addClient(this);
- stateChanged("ended");
+ stateChanged(QStringLiteral("ended"));
}
void DebugController::cleanup()
{
if (m_currentSession) m_currentSession.data()->stopDebugger();
}
DebugController::~DebugController()
{
}
BreakpointModel* DebugController::breakpointModel()
{
return m_breakpointModel;
}
VariableCollection* DebugController::variableCollection()
{
return m_variableCollection;
}
void DebugController::partAdded(KParts::Part* part)
{
if (KTextEditor::Document* doc = dynamic_cast(part)) {
KTextEditor::MarkInterface *iface = dynamic_cast(doc);
if( !iface )
return;
iface->setMarkPixmap(KTextEditor::MarkInterface::Execution, *executionPointPixmap());
}
}
IDebugSession* DebugController::currentSession()
{
return m_currentSession.data();
}
void DebugController::setupActions()
{
KActionCollection* ac = actionCollection();
- QAction* action = m_continueDebugger = new QAction(QIcon::fromTheme("media-playback-start"), i18n("&Continue"), this);
+ QAction* action = m_continueDebugger = new QAction(QIcon::fromTheme(QStringLiteral("media-playback-start")), i18n("&Continue"), this);
action->setToolTip( i18n("Continue application execution") );
action->setWhatsThis( i18n("Continues the execution of your application in the "
"debugger. This only takes effect when the application "
"has been halted by the debugger (i.e. a breakpoint has "
"been activated or the interrupt was pressed).") );
- ac->addAction("debug_continue", action);
+ ac->addAction(QStringLiteral("debug_continue"), action);
connect(action, &QAction::triggered, this, &DebugController::run);
#if 0
m_restartDebugger = action = new QAction(QIcon::fromTheme("media-seek-backward"), i18n("&Restart"), this);
action->setToolTip( i18n("Restart program") );
action->setWhatsThis( i18n("Restarts applications from the beginning.") );
action->setEnabled(false);
connect(action, SIGNAL(triggered(bool)), this, SLOT(restartDebugger()));
ac->addAction("debug_restart", action);
#endif
- m_interruptDebugger = action = new QAction(QIcon::fromTheme("media-playback-pause"), i18n("Interrupt"), this);
+ m_interruptDebugger = action = new QAction(QIcon::fromTheme(QStringLiteral("media-playback-pause")), i18n("Interrupt"), this);
action->setToolTip( i18n("Interrupt application") );
action->setWhatsThis(i18n("Interrupts the debugged process or current debugger command."));
connect(action, &QAction::triggered, this, &DebugController::interruptDebugger);
- ac->addAction("debug_pause", action);
+ ac->addAction(QStringLiteral("debug_pause"), action);
- m_runToCursor = action = new QAction(QIcon::fromTheme("debug-run-cursor"), i18n("Run to &Cursor"), this);
+ m_runToCursor = action = new QAction(QIcon::fromTheme(QStringLiteral("debug-run-cursor")), i18n("Run to &Cursor"), this);
action->setToolTip( i18n("Run to cursor") );
action->setWhatsThis(i18n("Continues execution until the cursor position is reached."));
connect(action, &QAction::triggered, this, &DebugController::runToCursor);
- ac->addAction("debug_runtocursor", action);
+ ac->addAction(QStringLiteral("debug_runtocursor"), action);
- m_jumpToCursor = action = new QAction(QIcon::fromTheme("debug-execute-to-cursor"), i18n("Set E&xecution Position to Cursor"), this);
+ m_jumpToCursor = action = new QAction(QIcon::fromTheme(QStringLiteral("debug-execute-to-cursor")), i18n("Set E&xecution Position to Cursor"), this);
action->setToolTip( i18n("Jump to cursor") );
action->setWhatsThis(i18n("Continue execution from the current cursor position."));
connect(action, &QAction::triggered, this, &DebugController::jumpToCursor);
- ac->addAction("debug_jumptocursor", action);
+ ac->addAction(QStringLiteral("debug_jumptocursor"), action);
- m_stepOver = action = new QAction(QIcon::fromTheme("debug-step-over"), i18n("Step &Over"), this);
+ m_stepOver = action = new QAction(QIcon::fromTheme(QStringLiteral("debug-step-over")), i18n("Step &Over"), this);
ac->setDefaultShortcut( action, Qt::Key_F10);
action->setToolTip( i18n("Step over the next line") );
action->setWhatsThis( i18n("Executes one line of source in the current source file. "
"If the source line is a call to a function the whole "
"function is executed and the app will stop at the line "
"following the function call.") );
connect(action, &QAction::triggered, this, &DebugController::stepOver);
- ac->addAction("debug_stepover", action);
+ ac->addAction(QStringLiteral("debug_stepover"), action);
- m_stepOverInstruction = action = new QAction(QIcon::fromTheme("debug-step-instruction"), i18n("Step over Ins&truction"), this);
+ m_stepOverInstruction = action = new QAction(QIcon::fromTheme(QStringLiteral("debug-step-instruction")), i18n("Step over Ins&truction"), this);
action->setToolTip( i18n("Step over instruction") );
action->setWhatsThis(i18n("Steps over the next assembly instruction."));
connect(action, &QAction::triggered, this, &DebugController::stepOverInstruction);
- ac->addAction("debug_stepoverinst", action);
+ ac->addAction(QStringLiteral("debug_stepoverinst"), action);
- m_stepInto = action = new QAction(QIcon::fromTheme("debug-step-into"), i18n("Step &Into"), this);
+ m_stepInto = action = new QAction(QIcon::fromTheme(QStringLiteral("debug-step-into")), i18n("Step &Into"), this);
ac->setDefaultShortcut( action, Qt::Key_F11);
action->setToolTip( i18n("Step into the next statement") );
action->setWhatsThis( i18n("Executes exactly one line of source. If the source line "
"is a call to a function then execution will stop after "
"the function has been entered.") );
connect(action, &QAction::triggered, this, &DebugController::stepInto);
- ac->addAction("debug_stepinto", action);
+ ac->addAction(QStringLiteral("debug_stepinto"), action);
- m_stepIntoInstruction = action = new QAction(QIcon::fromTheme("debug-step-into-instruction"), i18n("Step into I&nstruction"), this);
+ m_stepIntoInstruction = action = new QAction(QIcon::fromTheme(QStringLiteral("debug-step-into-instruction")), i18n("Step into I&nstruction"), this);
action->setToolTip( i18n("Step into instruction") );
action->setWhatsThis(i18n("Steps into the next assembly instruction."));
connect(action, &QAction::triggered, this, &DebugController::stepIntoInstruction);
- ac->addAction("debug_stepintoinst", action);
+ ac->addAction(QStringLiteral("debug_stepintoinst"), action);
- m_stepOut = action = new QAction(QIcon::fromTheme("debug-step-out"), i18n("Step O&ut"), this);
+ m_stepOut = action = new QAction(QIcon::fromTheme(QStringLiteral("debug-step-out")), i18n("Step O&ut"), this);
ac->setDefaultShortcut( action, Qt::Key_F12);
action->setToolTip( i18n("Step out of the current function") );
action->setWhatsThis( i18n("Executes the application until the currently executing "
"function is completed. The debugger will then display "
"the line after the original call to that function. If "
"program execution is in the outermost frame (i.e. in "
"main()) then this operation has no effect.") );
connect(action, &QAction::triggered, this, &DebugController::stepOut);
- ac->addAction("debug_stepout", action);
+ ac->addAction(QStringLiteral("debug_stepout"), action);
- m_toggleBreakpoint = action = new QAction(QIcon::fromTheme("script-error"), i18n("Toggle Breakpoint"), this);
+ m_toggleBreakpoint = action = new QAction(QIcon::fromTheme(QStringLiteral("script-error")), i18n("Toggle Breakpoint"), this);
ac->setDefaultShortcut( action, i18n("Ctrl+Alt+B") );
action->setToolTip(i18n("Toggle breakpoint"));
action->setWhatsThis(i18n("Toggles the breakpoint at the current line in editor."));
connect(action, &QAction::triggered, this, &DebugController::toggleBreakpoint);
- ac->addAction("debug_toggle_breakpoint", action);
+ ac->addAction(QStringLiteral("debug_toggle_breakpoint"), action);
}
void DebugController::addSession(IDebugSession* session)
{
qCDebug(SHELL) << session;
Q_ASSERT(session->variableController());
Q_ASSERT(session->breakpointController());
Q_ASSERT(session->frameStackModel());
//TODO support multiple sessions
if (m_currentSession) {
m_currentSession.data()->stopDebugger();
}
m_currentSession = session;
connect(session, &IDebugSession::stateChanged, this, &DebugController::debuggerStateChanged);
connect(session, &IDebugSession::showStepInSource, this, &DebugController::showStepInSource);
connect(session, &IDebugSession::clearExecutionPoint, this, &DebugController::clearExecutionPoint);
connect(session, &IDebugSession::raiseFramestackViews, this, &DebugController::raiseFramestackViews);
updateDebuggerState(session->state(), session);
emit currentSessionChanged(session);
if((Core::self()->setupFlags() & Core::NoUi)) return;
Sublime::MainWindow* mainWindow = Core::self()->uiControllerInternal()->activeSublimeWindow();
- if (mainWindow->area()->objectName() != "debug") {
+ if (mainWindow->area()->objectName() != QLatin1String("debug")) {
QString workingSet = mainWindow->area()->workingSet();
- ICore::self()->uiController()->switchToArea("debug", IUiController::ThisWindow);
+ ICore::self()->uiController()->switchToArea(QStringLiteral("debug"), IUiController::ThisWindow);
mainWindow->area()->setWorkingSet(workingSet);
connect(mainWindow, &Sublime::MainWindow::areaChanged, this, &DebugController::areaChanged);
}
}
void DebugController::clearExecutionPoint()
{
qCDebug(SHELL);
foreach (KDevelop::IDocument* document, KDevelop::ICore::self()->documentController()->openDocuments()) {
KTextEditor::MarkInterface *iface = dynamic_cast(document->textDocument());
if (!iface)
continue;
QHashIterator it = iface->marks();
while (it.hasNext())
{
KTextEditor::Mark* mark = it.next().value();
if( mark->type & KTextEditor::MarkInterface::Execution )
iface->removeMark( mark->line, KTextEditor::MarkInterface::Execution );
}
}
}
void DebugController::showStepInSource(const QUrl &url, int lineNum)
{
if((Core::self()->setupFlags() & Core::NoUi)) return;
clearExecutionPoint();
qCDebug(SHELL) << url << lineNum;
Q_ASSERT(dynamic_cast(sender()));
QPair openUrl = static_cast(sender())->convertToLocalUrl(qMakePair( url, lineNum ));
KDevelop::IDocument* document = KDevelop::ICore::self()
->documentController()
->openDocument(openUrl.first, KTextEditor::Cursor(openUrl.second, 0), IDocumentController::DoNotFocus);
if( !document )
return;
KTextEditor::MarkInterface *iface = dynamic_cast(document->textDocument());
if( !iface )
return;
document->textDocument()->blockSignals(true);
iface->addMark( lineNum, KTextEditor::MarkInterface::Execution );
document->textDocument()->blockSignals(false);
}
void DebugController::debuggerStateChanged(KDevelop::IDebugSession::DebuggerState state)
{
Q_ASSERT(dynamic_cast(sender()));
IDebugSession* session = static_cast(sender());
qCDebug(SHELL) << session << state << "current" << m_currentSession.data();
if (session == m_currentSession.data()) {
updateDebuggerState(state, session);
}
if (state == IDebugSession::EndedState) {
if (session == m_currentSession.data()) {
m_currentSession.clear();
emit currentSessionChanged(0);
if (!Core::self()->shuttingDown()) {
Sublime::MainWindow* mainWindow = Core::self()->uiControllerInternal()->activeSublimeWindow();
- if (mainWindow && mainWindow->area()->objectName() != "code") {
+ if (mainWindow && mainWindow->area()->objectName() != QLatin1String("code")) {
QString workingSet = mainWindow->area()->workingSet();
- ICore::self()->uiController()->switchToArea("code", IUiController::ThisWindow);
+ ICore::self()->uiController()->switchToArea(QStringLiteral("code"), IUiController::ThisWindow);
mainWindow->area()->setWorkingSet(workingSet);
}
ICore::self()->uiController()->findToolView(i18n("Debug"), 0, IUiController::Raise);
}
}
session->deleteLater();
}
}
void DebugController::updateDebuggerState(IDebugSession::DebuggerState state, IDebugSession *session)
{
Q_UNUSED(session);
if((Core::self()->setupFlags() & Core::NoUi)) return;
qCDebug(SHELL) << state;
switch (state) {
case IDebugSession::StoppedState:
case IDebugSession::NotStartedState:
case IDebugSession::StoppingState:
qCDebug(SHELL) << "new state: stopped";
- stateChanged("stopped");
+ stateChanged(QStringLiteral("stopped"));
//m_restartDebugger->setEnabled(session->restartAvailable());
break;
case IDebugSession::StartingState:
case IDebugSession::PausedState:
qCDebug(SHELL) << "new state: paused";
- stateChanged("paused");
+ stateChanged(QStringLiteral("paused"));
//m_restartDebugger->setEnabled(session->restartAvailable());
break;
case IDebugSession::ActiveState:
qCDebug(SHELL) << "new state: active";
- stateChanged("active");
+ stateChanged(QStringLiteral("active"));
//m_restartDebugger->setEnabled(false);
break;
case IDebugSession::EndedState:
qCDebug(SHELL) << "new state: ended";
- stateChanged("ended");
+ stateChanged(QStringLiteral("ended"));
//m_restartDebugger->setEnabled(false);
break;
}
if (state == IDebugSession::PausedState && ICore::self()->uiController()->activeMainWindow()) {
ICore::self()->uiController()->activeMainWindow()->activateWindow();
}
}
ContextMenuExtension DebugController::contextMenuExtension( Context* context )
{
ContextMenuExtension menuExt;
if( context->type() != Context::EditorContext )
return menuExt;
KDevelop::EditorContext *econtext = dynamic_cast(context);
if (!econtext)
return menuExt;
if (m_currentSession && m_currentSession.data()->isRunning()) {
menuExt.addAction( KDevelop::ContextMenuExtension::DebugGroup, m_runToCursor);
}
if (econtext->url().isLocalFile()) {
menuExt.addAction( KDevelop::ContextMenuExtension::DebugGroup, m_toggleBreakpoint);
}
return menuExt;
}
#if 0
void DebugController::restartDebugger() {
if (m_currentSession) {
m_currentSession.data()->restartDebugger();
}
}
#endif
void DebugController::stopDebugger() {
if (m_currentSession) {
m_currentSession.data()->stopDebugger();
}
}
void DebugController::interruptDebugger() {
if (m_currentSession) {
m_currentSession.data()->interruptDebugger();
}
}
void DebugController::run() {
if (m_currentSession) {
m_currentSession.data()->run();
}
}
void DebugController::runToCursor() {
if (m_currentSession) {
m_currentSession.data()->runToCursor();
}
}
void DebugController::jumpToCursor() {
if (m_currentSession) {
m_currentSession.data()->jumpToCursor();
}
}
void DebugController::stepOver() {
if (m_currentSession) {
m_currentSession.data()->stepOver();
}
}
void DebugController::stepIntoInstruction() {
if (m_currentSession) {
m_currentSession.data()->stepIntoInstruction();
}
}
void DebugController::stepInto() {
if (m_currentSession) {
m_currentSession.data()->stepInto();
}
}
void DebugController::stepOverInstruction() {
if (m_currentSession) {
m_currentSession.data()->stepOverInstruction();
}
}
void DebugController::stepOut() {
if (m_currentSession) {
m_currentSession.data()->stepOut();
}
}
void DebugController::areaChanged(Sublime::Area* newArea)
{
- if (newArea->objectName()!="debug") {
+ if (newArea->objectName()!=QLatin1String("debug")) {
stopDebugger();
}
}
void DebugController::toggleBreakpoint()
{
if (KDevelop::IDocument* document = KDevelop::ICore::self()->documentController()->activeDocument()) {
KTextEditor::Cursor cursor = document->cursorPosition();
if (!cursor.isValid()) return;
breakpointModel()->toggleBreakpoint(document->url(), cursor);
}
}
const QPixmap* DebugController::executionPointPixmap()
{
- static QPixmap pixmap=QIcon::fromTheme("go-next").pixmap(QSize(22,22), QIcon::Normal, QIcon::Off);
+ static QPixmap pixmap=QIcon::fromTheme(QStringLiteral("go-next")).pixmap(QSize(22,22), QIcon::Normal, QIcon::Off);
return &pixmap;
}
}
diff --git a/shell/documentationcontroller.cpp b/shell/documentationcontroller.cpp
index c517fa736e..35ba81e1bd 100644
--- a/shell/documentationcontroller.cpp
+++ b/shell/documentationcontroller.cpp
@@ -1,234 +1,234 @@
/*
Copyright 2009 Aleix Pol Gonzalez
Copyright 2010 Benjamin Port
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "documentationcontroller.h"
#include "debug.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace KDevelop;
namespace {
/**
* Return a "more useful" declaration that documentation providers can look-up
*
* @code
* QPoint point;
* ^-- cursor here
* @endcode
*
* In this case, this method returns a Declaration pointer to the *type*
* instead of a pointer to the instance, which is more useful when looking for help
*
* @return A more appropriate Declaration pointer or the given parameter @p decl
*/
Declaration* usefulDeclaration(Declaration* decl)
{
if (!decl)
return nullptr;
// First: Attempt to find the declaration of a definition
decl = DUChainUtils::declarationForDefinition(decl);
// Convenience feature: Retrieve the type declaration of instances,
// it makes no sense to pass the declaration pointer of instances of types
if (decl->kind() == Declaration::Instance) {
AbstractType::Ptr type = TypeUtils::targetTypeKeepAliases(decl->abstractType(), decl->topContext());
IdentifiedType* idType = dynamic_cast(type.data());
Declaration* idDecl = idType ? idType->declaration(decl->topContext()) : 0;
if (idDecl) {
decl = idDecl;
}
}
return decl;
}
}
class DocumentationViewFactory: public KDevelop::IToolViewFactory
{
public:
DocumentationViewFactory()
: mProvidersModel(0)
{}
QWidget* create( QWidget *parent = 0 ) override
{
return new DocumentationView( parent, providers() );
}
Qt::DockWidgetArea defaultPosition() override { return Qt::RightDockWidgetArea; }
- QString id() const override { return "org.kdevelop.DocumentationView"; }
+ QString id() const override { return QStringLiteral("org.kdevelop.DocumentationView"); }
private:
ProvidersModel* providers() {
if(!mProvidersModel)
mProvidersModel = new ProvidersModel;
return mProvidersModel;
}
ProvidersModel* mProvidersModel;
};
DocumentationController::DocumentationController(Core* core)
: m_factory(new DocumentationViewFactory)
{
- m_showDocumentation = core->uiController()->activeMainWindow()->actionCollection()->addAction("showDocumentation");
+ m_showDocumentation = core->uiController()->activeMainWindow()->actionCollection()->addAction(QStringLiteral("showDocumentation"));
m_showDocumentation->setText(i18n("Show Documentation"));
- m_showDocumentation->setIcon(QIcon::fromTheme("documentation"));
+ m_showDocumentation->setIcon(QIcon::fromTheme(QStringLiteral("documentation")));
connect(m_showDocumentation, &QAction::triggered, this, &DocumentationController::doShowDocumentation);
}
void DocumentationController::initialize()
{
if(!documentationProviders().isEmpty() && !(Core::self()->setupFlags() & Core::NoUi)) {
Core::self()->uiController()->addToolView( i18n("Documentation"), m_factory );
}
}
void KDevelop::DocumentationController::doShowDocumentation()
{
KTextEditor::View* view = ICore::self()->documentController()->activeTextDocumentView();
if(!view)
return;
KDevelop::DUChainReadLocker lock( DUChain::lock() );
Declaration* decl = usefulDeclaration(DUChainUtils::itemUnderCursor(view->document()->url(), KTextEditor::Cursor(view->cursorPosition())));
auto documentation = documentationForDeclaration(decl);
if (documentation) {
showDocumentation(documentation);
}
}
KDevelop::ContextMenuExtension KDevelop::DocumentationController::contextMenuExtension ( Context* context )
{
ContextMenuExtension menuExt;
DeclarationContext* ctx = dynamic_cast(context);
if(ctx) {
DUChainReadLocker lock(DUChain::lock());
if(!ctx->declaration().data())
return menuExt;
auto doc = documentationForDeclaration(ctx->declaration().data());
if (doc) {
menuExt.addAction(ContextMenuExtension::ExtensionGroup, m_showDocumentation);;
}
}
return menuExt;
}
IDocumentation::Ptr DocumentationController::documentationForDeclaration(Declaration* decl)
{
if (!decl)
return {};
foreach (IDocumentationProvider* doc, documentationProviders()) {
qCDebug(SHELL) << "Documentation provider found:" << doc;
auto ret = doc->documentationForDeclaration(decl);
qCDebug(SHELL) << "Documentation proposed: " << ret.data();
if (ret) {
return ret;
}
}
return {};
}
QList< IDocumentationProvider* > DocumentationController::documentationProviders() const
{
- QList plugins=ICore::self()->pluginController()->allPluginsForExtension("org.kdevelop.IDocumentationProvider");
- QList pluginsProvider=ICore::self()->pluginController()->allPluginsForExtension("org.kdevelop.IDocumentationProviderProvider");
+ QList plugins=ICore::self()->pluginController()->allPluginsForExtension(QStringLiteral("org.kdevelop.IDocumentationProvider"));
+ QList pluginsProvider=ICore::self()->pluginController()->allPluginsForExtension(QStringLiteral("org.kdevelop.IDocumentationProviderProvider"));
QList ret;
foreach(IPlugin* p, pluginsProvider)
{
IDocumentationProviderProvider *docProvider=p->extension();
if (!docProvider) {
qWarning() << "plugin" << p << "does not implement ProviderProvider extension, rerun kbuildsycoca5";
continue;
}
ret.append(docProvider->providers());
}
foreach(IPlugin* p, plugins)
{
IDocumentationProvider *doc=p->extension();
if (!doc) {
qWarning() << "plugin" << p << "does not implement Provider extension, rerun kbuildsycoca5";
continue;
}
ret.append(doc);
}
return ret;
}
void KDevelop::DocumentationController::showDocumentation(const IDocumentation::Ptr& doc)
{
QWidget* w = ICore::self()->uiController()->findToolView(i18n("Documentation"), m_factory, KDevelop::IUiController::CreateAndRaise);
if(!w) {
qWarning() << "Could not add documentation toolview";
return;
}
DocumentationView* view = dynamic_cast(w);
if( !view ) {
qWarning() << "Could not cast toolview" << w << "to DocumentationView class!";
return;
}
view->showDocumentation(doc);
}
void DocumentationController::changedDocumentationProviders()
{
emit providersChanged();
}
diff --git a/shell/documentcontroller.cpp b/shell/documentcontroller.cpp
index 3d833769c8..0176c2ea4d 100644
--- a/shell/documentcontroller.cpp
+++ b/shell/documentcontroller.cpp
@@ -1,1244 +1,1244 @@
/* This file is part of the KDE project
Copyright 2002 Matthias Hoelzer-Kluepfel
Copyright 2002 Bernd Gehrmann
Copyright 2003 Roberto Raggi
Copyright 2003-2008 Hamish Rodda
Copyright 2003 Harald Fernengel
Copyright 2003 Jens Dagerbo
Copyright 2005 Adam Treat
Copyright 2004-2007 Alexander Dymo
Copyright 2007 Andreas Pakulat
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "documentcontroller.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "core.h"
#include "mainwindow.h"
#include "textdocument.h"
#include "uicontroller.h"
#include "partcontroller.h"
#include "savedialog.h"
#include "debug.h"
#include
#include
#include
#include
#define EMPTY_DOCUMENT_URL i18n("Untitled")
namespace KDevelop
{
struct DocumentControllerPrivate
{
struct OpenFileResult
{
QList urls;
QString encoding;
};
DocumentControllerPrivate(DocumentController* c)
: controller(c)
, fileOpenRecent(0)
, globalTextEditorInstance(0)
{
}
~DocumentControllerPrivate()
{
//delete temporary files so they are removed from disk
foreach (QTemporaryFile *temp, tempFiles)
delete temp;
}
// used to map urls to open docs
QHash< QUrl, IDocument* > documents;
QHash< QString, IDocumentFactory* > factories;
QList tempFiles;
struct HistoryEntry
{
HistoryEntry() {}
HistoryEntry( const QUrl & u, const KTextEditor::Cursor& cursor );
QUrl url;
KTextEditor::Cursor cursor;
int id;
};
void removeDocument(Sublime::Document *doc)
{
QList urlsForDoc = documents.keys(dynamic_cast(doc));
foreach (const QUrl &url, urlsForDoc)
{
qCDebug(SHELL) << "destroying document" << doc;
documents.remove(url);
}
}
OpenFileResult showOpenFile() const
{
QUrl dir;
if ( controller->activeDocument() ) {
dir = controller->activeDocument()->url().adjusted(QUrl::RemoveFilename);
} else {
const auto cfg = KSharedConfig::openConfig()->group("Open File");
dir = cfg.readEntry( "Last Open File Directory", Core::self()->projectController()->projectsBaseDirectory() );
}
const auto caption = i18n("Open File");
const auto filter = i18n("*|Text File\n");
auto parent = Core::self()->uiControllerInternal()->defaultMainWindow();
// use special dialogs in a KDE session, native dialogs elsewhere
if (qEnvironmentVariableIsSet("KDE_FULL_SESSION")) {
const auto result = KEncodingFileDialog::getOpenUrlsAndEncoding(QString(), dir,
filter, parent, caption);
return {result.URLs, result.encoding};
}
// note: can't just filter on text files using the native dialog, just display all files
// see https://phabricator.kde.org/D622#11679
const auto urls = QFileDialog::getOpenFileUrls(parent, caption, dir);
return {urls, QString()};
}
void chooseDocument()
{
const auto res = showOpenFile();
if( !res.urls.isEmpty() ) {
QString encoding = res.encoding;
foreach( const QUrl& u, res.urls ) {
openDocumentInternal(u, QString(), KTextEditor::Range::invalid(), encoding );
}
}
}
void changeDocumentUrl(KDevelop::IDocument* document)
{
QMutableHashIterator it = documents;
while (it.hasNext()) {
if (it.next().value() == document) {
if (documents.contains(document->url())) {
// Weird situation (saving as a file that is aready open)
IDocument* origDoc = documents[document->url()];
if (origDoc->state() & IDocument::Modified) {
// given that the file has been saved, close the saved file as the other instance will become conflicted on disk
document->close();
controller->activateDocument( origDoc );
break;
}
// Otherwise close the original document
origDoc->close();
} else {
// Remove the original document
it.remove();
}
documents.insert(document->url(), document);
if (!controller->isEmptyDocumentUrl(document->url()))
{
fileOpenRecent->addUrl(document->url());
}
break;
}
}
}
KDevelop::IDocument* findBuddyDocument(const QUrl &url, IBuddyDocumentFinder* finder)
{
QList allDocs = controller->openDocuments();
foreach( KDevelop::IDocument* doc, allDocs ) {
if(finder->areBuddies(url, doc->url())) {
return doc;
}
}
return 0;
}
static bool fileExists(const QUrl& url)
{
if (url.isLocalFile()) {
return QFile::exists(url.toLocalFile());
} else {
auto job = KIO::stat(url, KIO::StatJob::SourceSide, 0);
KJobWidgets::setWindow(job, ICore::self()->uiController()->activeMainWindow());
return job->exec();
}
};
IDocument* openDocumentInternal( const QUrl & inputUrl, const QString& prefName = QString(),
const KTextEditor::Range& range = KTextEditor::Range::invalid(), const QString& encoding = QString(),
DocumentController::DocumentActivationParams activationParams = 0,
IDocument* buddy = 0)
{
Q_ASSERT(!inputUrl.isRelative());
Q_ASSERT(!inputUrl.fileName().isEmpty());
QString _encoding = encoding;
QUrl url = inputUrl;
if ( url.isEmpty() && (!activationParams.testFlag(IDocumentController::DoNotCreateView)) )
{
const auto res = showOpenFile();
if( !res.urls.isEmpty() )
url = res.urls.first();
_encoding = res.encoding;
if ( url.isEmpty() )
//still no url
return 0;
}
KSharedConfig::openConfig()->group("Open File").writeEntry( "Last Open File Directory", url.adjusted(QUrl::RemoveFilename) );
// clean it and resolve possible symlink
url = url.adjusted( QUrl::NormalizePathSegments );
if ( url.isLocalFile() )
{
QString path = QFileInfo( url.toLocalFile() ).canonicalFilePath();
if ( !path.isEmpty() )
url = QUrl::fromLocalFile( path );
}
//get a part document
IDocument* doc = documents.value(url);
if (!doc)
{
QMimeType mimeType;
if (DocumentController::isEmptyDocumentUrl(url))
{
- mimeType = QMimeDatabase().mimeTypeForName("text/plain");
+ mimeType = QMimeDatabase().mimeTypeForName(QStringLiteral("text/plain"));
}
else if (!url.isValid())
{
// Exit if the url is invalid (should not happen)
// If the url is valid and the file does not already exist,
// kate creates the file and gives a message saying so
qCDebug(SHELL) << "invalid URL:" << url.url();
return 0;
}
else if (KProtocolInfo::isKnownProtocol(url.scheme()) && !fileExists(url))
{
//Don't create a new file if we are not in the code mode.
- if (ICore::self()->uiController()->activeArea()->objectName() != "code") {
+ if (ICore::self()->uiController()->activeArea()->objectName() != QLatin1String("code")) {
return 0;
}
// enfore text mime type in order to create a kate part editor which then can be used to create the file
// otherwise we could end up opening e.g. okteta which then crashes, see: https://bugs.kde.org/id=326434
- mimeType = QMimeDatabase().mimeTypeForName("text/plain");
+ mimeType = QMimeDatabase().mimeTypeForName(QStringLiteral("text/plain"));
}
else
{
mimeType = QMimeDatabase().mimeTypeForUrl(url);
if(!url.isLocalFile() && mimeType.isDefault())
{
// fall back to text/plain, for remote files without extension, i.e. COPYING, LICENSE, ...
// using a synchronous KIO::MimetypeJob is hazardous and may lead to repeated calls to
// this function without it having returned in the first place
// and this function is *not* reentrant, see assert below:
// Q_ASSERT(!documents.contains(url) || documents[url]==doc);
- mimeType = QMimeDatabase().mimeTypeForName("text/plain");
+ mimeType = QMimeDatabase().mimeTypeForName(QStringLiteral("text/plain"));
}
}
// is the URL pointing to a directory?
if (mimeType.inherits(QStringLiteral("inode/directory")))
{
qCDebug(SHELL) << "cannot open directory:" << url.url();
return 0;
}
if( prefName.isEmpty() )
{
// Try to find a plugin that handles this mimetype
QVariantMap constraints;
- constraints.insert("X-KDevelop-SupportedMimeTypes", mimeType.name());
+ constraints.insert(QStringLiteral("X-KDevelop-SupportedMimeTypes"), mimeType.name());
Core::self()->pluginController()->pluginForExtension(QString(), QString(), constraints);
}
if( IDocumentFactory* factory = factories.value(mimeType.name()))
{
doc = factory->create(url, Core::self());
}
if(!doc) {
if( !prefName.isEmpty() )
{
doc = new PartDocument(url, Core::self(), prefName);
} else if ( Core::self()->partControllerInternal()->isTextType(mimeType))
{
doc = new TextDocument(url, Core::self(), _encoding);
} else if( Core::self()->partControllerInternal()->canCreatePart(url) )
{
doc = new PartDocument(url, Core::self());
} else
{
int openAsText = KMessageBox::questionYesNo(0, i18n("KDevelop could not find the editor for file '%1' of type %2.\nDo you want to open it as plain text?", url.fileName(), mimeType.name()), i18nc("@title:window", "Could Not Find Editor"),
- KStandardGuiItem::yes(), KStandardGuiItem::no(), "AskOpenWithTextEditor");
+ KStandardGuiItem::yes(), KStandardGuiItem::no(), QStringLiteral("AskOpenWithTextEditor"));
if (openAsText == KMessageBox::Yes)
doc = new TextDocument(url, Core::self(), _encoding);
else
return 0;
}
}
}
// The url in the document must equal the current url, else the housekeeping will get broken
Q_ASSERT(!doc || doc->url() == url);
if(doc && openDocumentInternal(doc, range, activationParams, buddy))
return doc;
else
return 0;
}
bool openDocumentInternal(IDocument* doc,
const KTextEditor::Range& range,
DocumentController::DocumentActivationParams activationParams,
IDocument* buddy = 0)
{
IDocument* previousActiveDocument = controller->activeDocument();
KTextEditor::View* previousActiveTextView = ICore::self()->documentController()->activeTextDocumentView();
KTextEditor::Cursor previousActivePosition;
if(previousActiveTextView)
previousActivePosition = previousActiveTextView->cursorPosition();
QUrl url=doc->url();
UiController *uiController = Core::self()->uiControllerInternal();
Sublime::Area *area = uiController->activeArea();
//We can't have the same url in many documents
//so we check it's already the same if it exists
//contains=>it's the same
Q_ASSERT(!documents.contains(url) || documents[url]==doc);
Sublime::Document *sdoc = dynamic_cast(doc);
if( !sdoc )
{
documents.remove(url);
delete doc;
return false;
}
//react on document deletion - we need to cleanup controller structures
QObject::connect(sdoc, &Sublime::Document::aboutToDelete, controller, &DocumentController::notifyDocumentClosed);
//We check if it was already opened before
bool emitOpened = !documents.contains(url);
if(emitOpened)
documents[url]=doc;
if (!activationParams.testFlag(IDocumentController::DoNotCreateView))
{
//find a view if there's one already opened in this area
Sublime::View *partView = 0;
Sublime::AreaIndex* activeViewIdx = area->indexOf(uiController->activeSublimeWindow()->activeView());
foreach (Sublime::View *view, sdoc->views())
{
Sublime::AreaIndex* areaIdx = area->indexOf(view);
if (areaIdx && areaIdx == activeViewIdx)
{
partView = view;
break;
}
}
bool addView = false;
if (!partView)
{
//no view currently shown for this url
partView = sdoc->createView();
addView = true;
}
if(addView) {
// This code is never executed when restoring session on startup,
// only when opening a file manually
Sublime::View* buddyView = 0;
bool placeAfterBuddy = true;
if(Core::self()->uiControllerInternal()->arrangeBuddies()) {
// If buddy is not set, look for a (usually) plugin which handles this URL's mimetype
// and use its IBuddyDocumentFinder, if available, to find a buddy document
if(!buddy && doc->mimeType().isValid()) {
QString mime = doc->mimeType().name();
IBuddyDocumentFinder* buddyFinder = IBuddyDocumentFinder::finderForMimeType(mime);
if(buddyFinder) {
buddy = findBuddyDocument(url, buddyFinder);
if(buddy) {
placeAfterBuddy = buddyFinder->buddyOrder(buddy->url(), doc->url());
}
}
}
if(buddy) {
Sublime::Document* sublimeDocBuddy = dynamic_cast(buddy);
if(sublimeDocBuddy) {
Sublime::AreaIndex *pActiveViewIndex = area->indexOf(uiController->activeSublimeWindow()->activeView());
if(pActiveViewIndex) {
// try to find existing View of buddy document in current active view's tab
foreach (Sublime::View *pView, pActiveViewIndex->views()) {
if(sublimeDocBuddy->views().contains(pView)) {
buddyView = pView;
break;
}
}
}
}
}
}
// add view to the area
if(buddyView && area->indexOf(buddyView)) {
if(placeAfterBuddy) {
// Adding new view after buddy view, simple case
area->addView(partView, area->indexOf(buddyView), buddyView);
}
else {
// First new view, then buddy view
area->addView(partView, area->indexOf(buddyView), buddyView);
// move buddyView tab after the new document
area->removeView(buddyView);
area->addView(buddyView, area->indexOf(partView), partView);
}
}
else {
// no buddy found for new document / plugin does not support buddies / buddy feature disabled
Sublime::View *activeView = uiController->activeSublimeWindow()->activeView();
Sublime::UrlDocument *activeDoc = 0;
IBuddyDocumentFinder *buddyFinder = 0;
if(activeView)
activeDoc = dynamic_cast(activeView->document());
if(activeDoc && Core::self()->uiControllerInternal()->arrangeBuddies()) {
QString mime = QMimeDatabase().mimeTypeForUrl(activeDoc->url()).name();
buddyFinder = IBuddyDocumentFinder::finderForMimeType(mime);
}
if(Core::self()->uiControllerInternal()->openAfterCurrent() &&
Core::self()->uiControllerInternal()->arrangeBuddies() &&
buddyFinder)
{
// Check if active document's buddy is directly next to it.
// For example, we have the already-open tabs | *foo.h* | foo.cpp | , foo.h is active.
// When we open a new document here (and the buddy feature is enabled),
// we do not want to separate foo.h and foo.cpp, so we take care and avoid this.
Sublime::AreaIndex *activeAreaIndex = area->indexOf(activeView);
int pos = activeAreaIndex->views().indexOf(activeView);
Sublime::View *afterActiveView = activeAreaIndex->views().value(pos+1, 0);
Sublime::UrlDocument *activeDoc = 0, *afterActiveDoc = 0;
if(activeView && afterActiveView) {
activeDoc = dynamic_cast(activeView->document());
afterActiveDoc = dynamic_cast(afterActiveView->document());
}
if(activeDoc && afterActiveDoc &&
buddyFinder->areBuddies(activeDoc->url(), afterActiveDoc->url()))
{
// don't insert in between of two buddies, but after them
area->addView(partView, activeAreaIndex, afterActiveView);
}
else {
// The active document's buddy is not directly after it
// => no ploblem, insert after active document
area->addView(partView, activeView);
}
}
else {
// Opening as last tab won't disturb our buddies
// Same, if buddies are disabled, we needn't care about them.
// this method places the tab according to openAfterCurrent()
area->addView(partView, activeView);
}
}
}
if (!activationParams.testFlag(IDocumentController::DoNotActivate))
{
uiController->activeSublimeWindow()->activateView(
partView, !activationParams.testFlag(IDocumentController::DoNotFocus));
}
if (!controller->isEmptyDocumentUrl(url))
{
fileOpenRecent->addUrl( url );
}
if( range.isValid() )
{
if (range.isEmpty())
doc->setCursorPosition( range.start() );
else
doc->setTextSelection( range );
}
}
// Deferred signals, wait until it's all ready first
if( emitOpened ) {
emit controller->documentOpened( doc );
}
if (!activationParams.testFlag(IDocumentController::DoNotActivate) && doc != controller->activeDocument())
emit controller->documentActivated( doc );
saveAll->setEnabled(true);
revertAll->setEnabled(true);
close->setEnabled(true);
closeAll->setEnabled(true);
closeAllOthers->setEnabled(true);
KTextEditor::Cursor activePosition;
if(range.isValid())
activePosition = range.start();
else if(KTextEditor::View* v = doc->activeTextView())
activePosition = v->cursorPosition();
if (doc != previousActiveDocument || activePosition != previousActivePosition)
emit controller->documentJumpPerformed(doc, activePosition, previousActiveDocument, previousActivePosition);
return true;
}
DocumentController* controller;
QList backHistory;
QList forwardHistory;
bool isJumping;
QPointer saveAll;
QPointer revertAll;
QPointer close;
QPointer closeAll;
QPointer closeAllOthers;
KRecentFilesAction* fileOpenRecent;
KTextEditor::Document* globalTextEditorInstance;
};
DocumentController::DocumentController( QObject *parent )
: IDocumentController( parent )
{
- setObjectName("DocumentController");
+ setObjectName(QStringLiteral("DocumentController"));
d = new DocumentControllerPrivate(this);
- QDBusConnection::sessionBus().registerObject( "/org/kdevelop/DocumentController",
+ QDBusConnection::sessionBus().registerObject( QStringLiteral("/org/kdevelop/DocumentController"),
this, QDBusConnection::ExportScriptableSlots );
connect(this, &DocumentController::documentUrlChanged, this, [&] (IDocument* document) { d->changeDocumentUrl(document); });
if(!(Core::self()->setupFlags() & Core::NoUi)) setupActions();
}
void DocumentController::initialize()
{
}
void DocumentController::cleanup()
{
if (d->fileOpenRecent)
d->fileOpenRecent->saveEntries( KConfigGroup(KSharedConfig::openConfig(), "Recent Files" ) );
// Close all documents without checking if they should be saved.
// This is because the user gets a chance to save them during MainWindow::queryClose.
foreach (IDocument* doc, openDocuments())
doc->close(IDocument::Discard);
}
DocumentController::~DocumentController()
{
delete d;
}
void DocumentController::setupActions()
{
KActionCollection* ac = Core::self()->uiControllerInternal()->defaultMainWindow()->actionCollection();
QAction* action;
- action = ac->addAction( "file_open" );
- action->setIcon(QIcon::fromTheme("document-open"));
+ action = ac->addAction( QStringLiteral("file_open") );
+ action->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
ac->setDefaultShortcut(action, Qt::CTRL + Qt::Key_O );
action->setText(i18n( "&Open..." ) );
connect( action, &QAction::triggered, this, [&] { d->chooseDocument(); } );
action->setToolTip( i18n( "Open file" ) );
action->setWhatsThis( i18n( "Opens a file for editing." ) );
d->fileOpenRecent = KStandardAction::openRecent(this,
SLOT(slotOpenDocument(QUrl)), ac);
d->fileOpenRecent->setWhatsThis(i18n("This lists files which you have opened recently, and allows you to easily open them again."));
d->fileOpenRecent->loadEntries( KConfigGroup(KSharedConfig::openConfig(), "Recent Files" ) );
- action = d->saveAll = ac->addAction( "file_save_all" );
- action->setIcon(QIcon::fromTheme("document-save"));
+ action = d->saveAll = ac->addAction( QStringLiteral("file_save_all") );
+ action->setIcon(QIcon::fromTheme(QStringLiteral("document-save")));
action->setText(i18n( "Save Al&l" ) );
connect( action, &QAction::triggered, this, &DocumentController::slotSaveAllDocuments );
action->setToolTip( i18n( "Save all open documents" ) );
action->setWhatsThis( i18n( "Save all open documents, prompting for additional information when necessary." ) );
ac->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_L) );
action->setEnabled(false);
- action = d->revertAll = ac->addAction( "file_revert_all" );
- action->setIcon(QIcon::fromTheme("document-revert"));
+ action = d->revertAll = ac->addAction( QStringLiteral("file_revert_all") );
+ action->setIcon(QIcon::fromTheme(QStringLiteral("document-revert")));
action->setText(i18n( "Reload All" ) );
connect( action, &QAction::triggered, this, &DocumentController::reloadAllDocuments );
action->setToolTip( i18n( "Revert all open documents" ) );
action->setWhatsThis( i18n( "Revert all open documents, returning to the previously saved state." ) );
action->setEnabled(false);
- action = d->close = ac->addAction( "file_close" );
- action->setIcon(QIcon::fromTheme("window-close"));
+ action = d->close = ac->addAction( QStringLiteral("file_close") );
+ action->setIcon(QIcon::fromTheme(QStringLiteral("window-close")));
ac->setDefaultShortcut(action, Qt::CTRL + Qt::Key_W );
action->setText( i18n( "&Close" ) );
connect( action, &QAction::triggered, this, &DocumentController::fileClose );
action->setToolTip( i18n( "Close file" ) );
action->setWhatsThis( i18n( "Closes current file." ) );
action->setEnabled(false);
- action = d->closeAll = ac->addAction( "file_close_all" );
- action->setIcon(QIcon::fromTheme("window-close"));
+ action = d->closeAll = ac->addAction( QStringLiteral("file_close_all") );
+ action->setIcon(QIcon::fromTheme(QStringLiteral("window-close")));
action->setText(i18n( "Clos&e All" ) );
connect( action, &QAction::triggered, this, &DocumentController::closeAllDocuments );
action->setToolTip( i18n( "Close all open documents" ) );
action->setWhatsThis( i18n( "Close all open documents, prompting for additional information when necessary." ) );
action->setEnabled(false);
- action = d->closeAllOthers = ac->addAction( "file_closeother" );
- action->setIcon(QIcon::fromTheme("window-close"));
+ action = d->closeAllOthers = ac->addAction( QStringLiteral("file_closeother") );
+ action->setIcon(QIcon::fromTheme(QStringLiteral("window-close")));
ac->setDefaultShortcut(action, Qt::CTRL + Qt::SHIFT + Qt::Key_W );
action->setText(i18n( "Close All Ot&hers" ) );
connect( action, &QAction::triggered, this, &DocumentController::closeAllOtherDocuments );
action->setToolTip( i18n( "Close all other documents" ) );
action->setWhatsThis( i18n( "Close all open documents, with the exception of the currently active document." ) );
action->setEnabled(false);
- action = ac->addAction( "vcsannotate_current_document" );
+ action = ac->addAction( QStringLiteral("vcsannotate_current_document") );
connect( action, &QAction::triggered, this, &DocumentController::vcsAnnotateCurrentDocument );
action->setText( i18n( "Show Annotate on current document") );
action->setIconText( i18n( "Annotate" ) );
- action->setIcon( QIcon::fromTheme("user-properties") );
+ action->setIcon( QIcon::fromTheme(QStringLiteral("user-properties")) );
}
void DocumentController::slotOpenDocument(const QUrl &url)
{
openDocument(url);
}
IDocument* DocumentController::openDocumentFromText( const QString& data )
{
IDocument* d = openDocument(nextEmptyDocumentUrl());
Q_ASSERT(d->textDocument());
d->textDocument()->setText( data );
return d;
}
bool DocumentController::openDocumentFromTextSimple( QString text )
{
return (bool)openDocumentFromText( text );
}
bool DocumentController::openDocumentSimple( QString url, int line, int column )
{
return (bool)openDocument( QUrl::fromUserInput(url), KTextEditor::Cursor( line, column ) );
}
IDocument* DocumentController::openDocument( const QUrl& inputUrl, const QString& prefName )
{
return d->openDocumentInternal( inputUrl, prefName );
}
IDocument* DocumentController::openDocument( const QUrl & inputUrl,
const KTextEditor::Range& range,
DocumentActivationParams activationParams,
const QString& encoding, IDocument* buddy)
{
- return d->openDocumentInternal( inputUrl, "", range, encoding, activationParams, buddy);
+ return d->openDocumentInternal( inputUrl, QLatin1String(""), range, encoding, activationParams, buddy);
}
bool DocumentController::openDocument(IDocument* doc,
const KTextEditor::Range& range,
DocumentActivationParams activationParams,
IDocument* buddy)
{
return d->openDocumentInternal( doc, range, activationParams, buddy);
}
void DocumentController::fileClose()
{
IDocument *activeDoc = activeDocument();
if (activeDoc)
{
UiController *uiController = Core::self()->uiControllerInternal();
Sublime::View *activeView = uiController->activeSublimeWindow()->activeView();
uiController->activeArea()->closeView(activeView);
}
}
void DocumentController::closeDocument( const QUrl &url )
{
if( !d->documents.contains(url) )
return;
//this will remove all views and after the last view is removed, the
//document will be self-destructed and removeDocument() slot will catch that
//and clean up internal data structures
d->documents[url]->close();
}
void DocumentController::notifyDocumentClosed(Sublime::Document* doc_)
{
IDocument* doc = dynamic_cast(doc_);
Q_ASSERT(doc);
d->removeDocument(doc_);
if (d->documents.isEmpty()) {
if (d->saveAll)
d->saveAll->setEnabled(false);
if (d->revertAll)
d->revertAll->setEnabled(false);
if (d->close)
d->close->setEnabled(false);
if (d->closeAll)
d->closeAll->setEnabled(false);
if (d->closeAllOthers)
d->closeAllOthers->setEnabled(false);
}
emit documentClosed(doc);
}
IDocument * DocumentController::documentForUrl( const QUrl & dirtyUrl ) const
{
if (dirtyUrl.isEmpty()) {
return nullptr;
}
Q_ASSERT(!dirtyUrl.isRelative());
Q_ASSERT(!dirtyUrl.fileName().isEmpty());
//Fix urls that might not be normalized
return d->documents.value( dirtyUrl.adjusted( QUrl::NormalizePathSegments ), 0 );
}
QList DocumentController::openDocuments() const
{
QList opened;
foreach (IDocument *doc, d->documents)
{
Sublime::Document *sdoc = dynamic_cast(doc);
if( !sdoc )
{
continue;
}
if (!sdoc->views().isEmpty())
opened << doc;
}
return opened;
}
void DocumentController::activateDocument( IDocument * document, const KTextEditor::Range& range )
{
// TODO avoid some code in openDocument?
Q_ASSERT(document);
openDocument(document->url(), range);
}
void DocumentController::slotSaveAllDocuments()
{
saveAllDocuments(IDocument::Silent);
}
bool DocumentController::saveAllDocuments(IDocument::DocumentSaveMode mode)
{
return saveSomeDocuments(openDocuments(), mode);
}
bool KDevelop::DocumentController::saveSomeDocuments(const QList< IDocument * > & list, IDocument::DocumentSaveMode mode)
{
if (mode & IDocument::Silent) {
foreach (IDocument* doc, modifiedDocuments(list)) {
if( !DocumentController::isEmptyDocumentUrl(doc->url()) && !doc->save(mode) )
{
if( doc )
qWarning() << "!! Could not save document:" << doc->url();
else
qWarning() << "!! Could not save document as its NULL";
}
// TODO if (!ret) showErrorDialog() ?
}
} else {
// Ask the user which documents to save
QList checkSave = modifiedDocuments(list);
if (!checkSave.isEmpty()) {
KSaveSelectDialog dialog(checkSave, qApp->activeWindow());
if (dialog.exec() == QDialog::Rejected)
return false;
}
}
return true;
}
QList< IDocument * > KDevelop::DocumentController::visibleDocumentsInWindow(MainWindow * mw) const
{
// Gather a list of all documents which do have a view in the given main window
// Does not find documents which are open in inactive areas
QList list;
foreach (IDocument* doc, openDocuments()) {
if (Sublime::Document* sdoc = dynamic_cast(doc)) {
foreach (Sublime::View* view, sdoc->views()) {
if (view->hasWidget() && view->widget()->window() == mw) {
list.append(doc);
break;
}
}
}
}
return list;
}
QList< IDocument * > KDevelop::DocumentController::documentsExclusivelyInWindow(MainWindow * mw, bool currentAreaOnly) const
{
// Gather a list of all documents which have views only in the given main window
QList checkSave;
foreach (IDocument* doc, openDocuments()) {
if (Sublime::Document* sdoc = dynamic_cast(doc)) {
bool inOtherWindow = false;
foreach (Sublime::View* view, sdoc->views()) {
foreach(Sublime::MainWindow* window, Core::self()->uiControllerInternal()->mainWindows())
if(window->containsView(view) && (window != mw || (currentAreaOnly && window == mw && !mw->area()->views().contains(view))))
inOtherWindow = true;
}
if (!inOtherWindow)
checkSave.append(doc);
}
}
return checkSave;
}
QList< IDocument * > KDevelop::DocumentController::modifiedDocuments(const QList< IDocument * > & list) const
{
QList< IDocument * > ret;
foreach (IDocument* doc, list)
if (doc->state() == IDocument::Modified || doc->state() == IDocument::DirtyAndModified)
ret.append(doc);
return ret;
}
bool DocumentController::saveAllDocumentsForWindow(KParts::MainWindow* mw, KDevelop::IDocument::DocumentSaveMode mode, bool currentAreaOnly)
{
QList checkSave = documentsExclusivelyInWindow(dynamic_cast(mw), currentAreaOnly);
return saveSomeDocuments(checkSave, mode);
}
void DocumentController::reloadAllDocuments()
{
if (Sublime::MainWindow* mw = Core::self()->uiControllerInternal()->activeSublimeWindow()) {
QList views = visibleDocumentsInWindow(dynamic_cast(mw));
if (!saveSomeDocuments(views, IDocument::Default))
// User cancelled or other error
return;
foreach (IDocument* doc, views)
if(!isEmptyDocumentUrl(doc->url()))
doc->reload();
}
}
bool DocumentController::closeAllDocuments()
{
if (Sublime::MainWindow* mw = Core::self()->uiControllerInternal()->activeSublimeWindow()) {
QList views = visibleDocumentsInWindow(dynamic_cast(mw));
if (!saveSomeDocuments(views, IDocument::Default))
// User cancelled or other error
return false;
foreach (IDocument* doc, views)
doc->close(IDocument::Discard);
}
return true;
}
void DocumentController::closeAllOtherDocuments()
{
if (Sublime::MainWindow* mw = Core::self()->uiControllerInternal()->activeSublimeWindow()) {
Sublime::View* activeView = mw->activeView();
if (!activeView) {
qWarning() << "Shouldn't there always be an active view when this function is called?";
return;
}
// Deal with saving unsaved solo views
QList soloViews = documentsExclusivelyInWindow(dynamic_cast(mw));
soloViews.removeAll(dynamic_cast(activeView->document()));
if (!saveSomeDocuments(soloViews, IDocument::Default))
// User cancelled or other error
return;
foreach (Sublime::View* view, mw->area()->views()) {
if (view != activeView)
mw->area()->closeView(view);
}
activeView->widget()->setFocus();
}
}
IDocument* DocumentController::activeDocument() const
{
UiController *uiController = Core::self()->uiControllerInternal();
Sublime::MainWindow* mw = uiController->activeSublimeWindow();
if( !mw || !mw->activeView() ) return 0;
return dynamic_cast(mw->activeView()->document());
}
KTextEditor::View* DocumentController::activeTextDocumentView() const
{
UiController *uiController = Core::self()->uiControllerInternal();
Sublime::MainWindow* mw = uiController->activeSublimeWindow();
if( !mw || !mw->activeView() )
return 0;
TextView* view = qobject_cast(mw->activeView());
if(!view)
return 0;
return view->textView();
}
QString DocumentController::activeDocumentPath( QString target ) const
{
- if(target.size()) {
+ if(!target.isEmpty()) {
foreach(IProject* project, Core::self()->projectController()->projects()) {
if(project->name().startsWith(target, Qt::CaseInsensitive)) {
return project->path().pathOrUrl() + "/.";
}
}
}
IDocument* doc = activeDocument();
- if(!doc || target == "[selection]")
+ if(!doc || target == QStringLiteral("[selection]"))
{
Context* selection = ICore::self()->selectionController()->currentSelection();
- if(selection && selection->type() == Context::ProjectItemContext && static_cast(selection)->items().size())
+ if(selection && selection->type() == Context::ProjectItemContext && !static_cast(selection)->items().isEmpty())
{
- QString ret = static_cast(selection)->items()[0]->path().pathOrUrl();
- if(static_cast(selection)->items()[0]->folder())
- ret += "/.";
+ QString ret = static_cast(selection)->items().at(0)->path().pathOrUrl();
+ if(static_cast(selection)->items().at(0)->folder())
+ ret += QStringLiteral("/.");
return ret;
}
return QString();
}
return doc->url().toString();
}
QStringList DocumentController::activeDocumentPaths() const
{
UiController *uiController = Core::self()->uiControllerInternal();
if( !uiController->activeSublimeWindow() ) return QStringList();
QSet documents;
foreach(Sublime::View* view, uiController->activeSublimeWindow()->area()->views())
documents.insert(view->document()->documentSpecifier());
return documents.toList();
}
void DocumentController::registerDocumentForMimetype( const QString& mimetype,
KDevelop::IDocumentFactory* factory )
{
if( !d->factories.contains( mimetype ) )
d->factories[mimetype] = factory;
}
QStringList DocumentController::documentTypes() const
{
- return QStringList() << "Text";
+ return QStringList() << QStringLiteral("Text");
}
static const QRegularExpression& emptyDocumentPattern()
{
static const QRegularExpression pattern(QStringLiteral("^/%1(?:\\s\\((\\d+)\\))?$").arg(EMPTY_DOCUMENT_URL));
return pattern;
}
bool DocumentController::isEmptyDocumentUrl(const QUrl &url)
{
return emptyDocumentPattern().match(url.toDisplayString(QUrl::PreferLocalFile)).hasMatch();
}
QUrl DocumentController::nextEmptyDocumentUrl()
{
int nextEmptyDocNumber = 0;
const auto& pattern = emptyDocumentPattern();
foreach (IDocument *doc, Core::self()->documentControllerInternal()->openDocuments()) {
if (DocumentController::isEmptyDocumentUrl(doc->url())) {
const auto match = pattern.match(doc->url().toDisplayString(QUrl::PreferLocalFile));
if (match.hasMatch()) {
const int num = match.captured(1).toInt();
nextEmptyDocNumber = qMax(nextEmptyDocNumber, num + 1);
} else {
nextEmptyDocNumber = qMax(nextEmptyDocNumber, 1);
}
}
}
QUrl url;
if (nextEmptyDocNumber > 0)
url = QUrl::fromLocalFile(QStringLiteral("/%1 (%2)").arg(EMPTY_DOCUMENT_URL).arg(nextEmptyDocNumber));
else
url = QUrl::fromLocalFile('/' + EMPTY_DOCUMENT_URL);
return url;
}
IDocumentFactory* DocumentController::factory(const QString& mime) const
{
return d->factories.value(mime);
}
KTextEditor::Document* DocumentController::globalTextEditorInstance()
{
if(!d->globalTextEditorInstance)
d->globalTextEditorInstance = Core::self()->partControllerInternal()->createTextPart();
return d->globalTextEditorInstance;
}
bool DocumentController::openDocumentsSimple( QStringList urls )
{
Sublime::Area* area = Core::self()->uiControllerInternal()->activeArea();
Sublime::AreaIndex* areaIndex = area->rootIndex();
QList topViews = static_cast(Core::self()->uiControllerInternal()->activeMainWindow())->getTopViews();
if(Sublime::View* activeView = Core::self()->uiControllerInternal()->activeSublimeWindow()->activeView())
areaIndex = area->indexOf(activeView);
qCDebug(SHELL) << "opening " << urls << " to area " << area << " index " << areaIndex << " with children " << areaIndex->first() << " " << areaIndex->second();
bool isFirstView = true;
bool ret = openDocumentsWithSplitSeparators( areaIndex, urls, isFirstView );
qCDebug(SHELL) << "area arch. after opening: " << areaIndex->print();
// Required because sublime sometimes doesn't update correctly when the area-index contents has been changed
// (especially when views have been moved to other indices, through unsplit, split, etc.)
static_cast(Core::self()->uiControllerInternal()->activeMainWindow())->reconstructViews(topViews);
return ret;
}
bool DocumentController::openDocumentsWithSplitSeparators( Sublime::AreaIndex* index, QStringList urlsWithSeparators, bool& isFirstView )
{
qCDebug(SHELL) << "opening " << urlsWithSeparators << " index " << index << " with children " << index->first() << " " << index->second() << " view-count " << index->viewCount();
if(urlsWithSeparators.isEmpty())
return true;
Sublime::Area* area = Core::self()->uiControllerInternal()->activeArea();
QList topLevelSeparators; // Indices of the top-level separators (with groups skipped)
- QStringList separators = QStringList() << "/" << "-";
+ QStringList separators = QStringList() << QStringLiteral("/") << QStringLiteral("-");
QList groups;
bool ret = true;
{
int parenDepth = 0;
int groupStart = 0;
for(int pos = 0; pos < urlsWithSeparators.size(); ++pos)
{
QString item = urlsWithSeparators[pos];
if(separators.contains(item))
{
if(parenDepth == 0)
topLevelSeparators << pos;
- }else if(item == "[")
+ }else if(item == QLatin1String("["))
{
if(parenDepth == 0)
groupStart = pos+1;
++parenDepth;
}
- else if(item == "]")
+ else if(item == QLatin1String("]"))
{
if(parenDepth > 0)
{
--parenDepth;
if(parenDepth == 0)
groups << urlsWithSeparators.mid(groupStart, pos-groupStart);
}
else{
qCDebug(SHELL) << "syntax error in " << urlsWithSeparators << ": parens do not match";
ret = false;
}
}else if(parenDepth == 0)
{
groups << (QStringList() << item);
}
}
}
if(topLevelSeparators.isEmpty())
{
if(urlsWithSeparators.size() > 1)
{
foreach(const QStringList& group, groups)
ret &= openDocumentsWithSplitSeparators( index, group, isFirstView );
}else{
while(index->isSplit())
index = index->first();
// Simply open the document into the area index
IDocument* doc = Core::self()->documentControllerInternal()->openDocument(QUrl::fromUserInput(urlsWithSeparators.front()),
KTextEditor::Cursor::invalid(),
IDocumentController::DoNotActivate | IDocumentController::DoNotCreateView);
Sublime::Document *sublimeDoc = dynamic_cast(doc);
if (sublimeDoc) {
Sublime::View* view = sublimeDoc->createView();
area->addView(view, index);
if(isFirstView)
{
static_cast(Core::self()->uiControllerInternal()->activeMainWindow())->activateView(view);
isFirstView = false;
}
}else{
ret = false;
}
}
return ret;
}
// Pick a separator in the middle
int pickSeparator = topLevelSeparators[topLevelSeparators.size()/2];
bool activeViewToSecondChild = false;
if(pickSeparator == urlsWithSeparators.size()-1)
{
// There is no right child group, so the right side should be filled with the currently active views
activeViewToSecondChild = true;
}else{
QStringList separatorsAndParens = separators;
- separatorsAndParens << "[" << "]";
+ separatorsAndParens << QStringLiteral("[") << QStringLiteral("]");
// Check if the second child-set contains an unterminated separator, which means that the active views should end up there
for(int pos = pickSeparator+1; pos < urlsWithSeparators.size(); ++pos)
if( separators.contains(urlsWithSeparators[pos]) && (pos == urlsWithSeparators.size()-1 ||
separatorsAndParens.contains(urlsWithSeparators[pos-1]) ||
separatorsAndParens.contains(urlsWithSeparators[pos-1])) )
activeViewToSecondChild = true;
}
- Qt::Orientation orientation = urlsWithSeparators[pickSeparator] == "/" ? Qt::Horizontal : Qt::Vertical;
+ Qt::Orientation orientation = urlsWithSeparators[pickSeparator] == QLatin1String("/") ? Qt::Horizontal : Qt::Vertical;
if(!index->isSplit())
{
qCDebug(SHELL) << "splitting " << index << "orientation" << orientation << "to second" << activeViewToSecondChild;
index->split(orientation, activeViewToSecondChild);
}else{
index->setOrientation(orientation);
qCDebug(SHELL) << "WARNING: Area is already split (shouldn't be)" << urlsWithSeparators;
}
openDocumentsWithSplitSeparators( index->first(), urlsWithSeparators.mid(0, pickSeparator) , isFirstView );
if(pickSeparator != urlsWithSeparators.size() - 1)
openDocumentsWithSplitSeparators( index->second(), urlsWithSeparators.mid(pickSeparator+1, urlsWithSeparators.size() - (pickSeparator+1) ), isFirstView );
// Clean up the child-indices, because document-loading may fail
if(!index->first()->viewCount() && !index->first()->isSplit())
{
qCDebug(SHELL) << "unsplitting first";
index->unsplit(index->first());
}
else if(!index->second()->viewCount() && !index->second()->isSplit())
{
qCDebug(SHELL) << "unsplitting second";
index->unsplit(index->second());
}
return ret;
}
void DocumentController::vcsAnnotateCurrentDocument()
{
IDocument* doc = activeDocument();
QUrl url = doc->url();
IProject* project = KDevelop::ICore::self()->projectController()->findProjectForUrl(url);
if(project && project->versionControlPlugin()) {
IBasicVersionControl* iface = 0;
iface = project->versionControlPlugin()->extension();
auto helper = new VcsPluginHelper(project->versionControlPlugin(), iface);
connect(doc->textDocument(), &KTextEditor::Document::aboutToClose,
helper, static_cast(&VcsPluginHelper::disposeEventually));
Q_ASSERT(qobject_cast(doc->activeTextView()));
// can't use new signal slot syntax here, AnnotationViewInterface is not a QObject
connect(doc->activeTextView(), SIGNAL(annotationBorderVisibilityChanged(View*,bool)),
helper, SLOT(disposeEventually(View*, bool)));
helper->addContextDocument(url);
helper->annotation();
}
else {
KMessageBox::error(0, i18n("Could not annotate the document because it is not "
"part of a version-controlled project."));
}
}
}
#include "moc_documentcontroller.cpp"
diff --git a/shell/editorconfigpage.cpp b/shell/editorconfigpage.cpp
index 34f4c1cbb7..a34b9d91c3 100644
--- a/shell/editorconfigpage.cpp
+++ b/shell/editorconfigpage.cpp
@@ -1,127 +1,127 @@
/*
* This file is part of KDevelop
* Copyright 2014 Alex Richardson
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3, or any
* later version accepted by the membership of KDE e.V. (or its
* successor approved by the membership of KDE e.V.), which shall
* act as a proxy defined in Section 6 of version 3 of the license.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*/
#include "editorconfigpage.h"
#include
#include
#include
#include