Commit 34fd3256 authored by Eike Ziller's avatar Eike Ziller

Merge remote-tracking branch 'origin/master' into 4.0

Change-Id: I07981129945f5a78f3ec4a4740a983c613b41e48
parents 4babde7d 19c8c9bc
......@@ -23,5 +23,4 @@
**
****************************************************************************/
#include "multitask.h"
#include "runextensions.h"
......@@ -359,7 +359,7 @@ void cleanUpFileSearch(QFutureInterface<FileSearchResultList> &futureInterface,
QFuture<FileSearchResultList> Utils::findInFiles(const QString &searchTerm, FileIterator *files,
QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap)
{
return mapReduce(std::cref(*files),
return mapReduce(files->begin(), files->end(),
[searchTerm, files](QFutureInterface<FileSearchResultList> &futureInterface) {
return initFileSearch(futureInterface, searchTerm, files);
},
......@@ -371,7 +371,7 @@ QFuture<FileSearchResultList> Utils::findInFiles(const QString &searchTerm, File
QFuture<FileSearchResultList> Utils::findInFilesRegExp(const QString &searchTerm, FileIterator *files,
QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap)
{
return mapReduce(std::cref(*files),
return mapReduce(files->begin(), files->end(),
[searchTerm, files](QFutureInterface<FileSearchResultList> &futureInterface) {
return initFileSearch(futureInterface, searchTerm, files);
},
......@@ -494,14 +494,8 @@ void FileIterator::advance(FileIterator::const_iterator *it) const
return;
++it->m_index;
const_cast<FileIterator *>(this)->update(it->m_index);
if (it->m_index < currentFileCount()) {
it->m_item.filePath = fileAt(it->m_index);
it->m_item.encoding = codecAt(it->m_index);
} else {
if (it->m_index >= currentFileCount())
it->m_index = -1; // == end
it->m_item.filePath.clear();
it->m_item.encoding = 0;
}
}
FileIterator::const_iterator FileIterator::begin() const
......@@ -509,25 +503,30 @@ FileIterator::const_iterator FileIterator::begin() const
const_cast<FileIterator *>(this)->update(0);
if (currentFileCount() == 0)
return end();
return FileIterator::const_iterator(this,
FileIterator::Item(fileAt(0), codecAt(0)),
0/*index*/);
return FileIterator::const_iterator(this, 0/*index*/);
}
FileIterator::const_iterator FileIterator::end() const
{
return FileIterator::const_iterator(this, FileIterator::Item(QString(), 0),
-1/*end*/);
return FileIterator::const_iterator(this, -1/*end*/);
}
// #pragma mark -- FileListIterator
QTextCodec *encodingAt(const QList<QTextCodec *> encodings, int index)
{
if (index >= 0 && index < encodings.size())
return encodings.at(index);
return QTextCodec::codecForLocale();
}
FileListIterator::FileListIterator(const QStringList &fileList,
const QList<QTextCodec *> encodings)
: m_files(fileList),
m_encodings(encodings),
m_maxIndex(-1)
: m_maxIndex(-1)
{
m_items.reserve(fileList.size());
for (int i = 0; i < fileList.size(); ++i)
m_items.append(Item(fileList.at(i), encodingAt(encodings, i)));
}
void FileListIterator::update(int requestedIndex)
......@@ -538,22 +537,17 @@ void FileListIterator::update(int requestedIndex)
int FileListIterator::currentFileCount() const
{
return m_files.size();
return m_items.size();
}
QString FileListIterator::fileAt(int index) const
const FileIterator::Item &FileListIterator::itemAt(int index) const
{
return m_files.at(index);
}
QTextCodec *FileListIterator::codecAt(int index) const
{
return m_encodings.at(index);
return m_items.at(index);
}
int FileListIterator::maxProgress() const
{
return m_files.size();
return m_items.size();
}
int FileListIterator::currentProgress() const
......@@ -561,13 +555,6 @@ int FileListIterator::currentProgress() const
return m_maxIndex + 1;
}
QTextCodec *FileListIterator::encodingAt(int index) const
{
if (index >= 0 && index < m_encodings.size())
return m_encodings.at(index);
return QTextCodec::codecForLocale();
}
// #pragma mark -- SubDirFileIterator
namespace {
......@@ -589,12 +576,17 @@ SubDirFileIterator::SubDirFileIterator(const QStringList &directories, const QSt
}
}
SubDirFileIterator::~SubDirFileIterator()
{
qDeleteAll(m_items);
}
void SubDirFileIterator::update(int index)
{
if (index < m_files.size())
if (index < m_items.size())
return;
// collect files from the directories until we have enough for the given index
while (!m_dirs.isEmpty() && index >= m_files.size()) {
while (!m_dirs.isEmpty() && index >= m_items.size()) {
QDir dir = m_dirs.pop();
const qreal dirProgressMax = m_progressValues.pop();
const bool processed = m_processedValues.pop();
......@@ -607,9 +599,10 @@ void SubDirFileIterator::update(int index)
QDir::Files|QDir::Hidden);
QStringListIterator it(fileEntries);
it.toBack();
m_items.reserve(m_items.size() + fileEntries.size());
while (it.hasPrevious()) {
const QString &file = it.previous();
m_files.append(dir.path()+ QLatin1Char('/') +file);
m_items.append(new Item(dir.path()+ QLatin1Char('/') + file, m_encoding));
}
m_progress += dirProgressMax;
} else {
......@@ -630,24 +623,18 @@ void SubDirFileIterator::update(int index)
m_progress += dirProgressMax;
}
}
if (index >= m_files.size())
if (index >= m_items.size())
m_progress = MAX_PROGRESS;
}
int SubDirFileIterator::currentFileCount() const
{
return m_files.size();
}
QString SubDirFileIterator::fileAt(int index) const
{
return m_files.at(index);
return m_items.size();
}
QTextCodec *SubDirFileIterator::codecAt(int index) const
const FileIterator::Item &SubDirFileIterator::itemAt(int index) const
{
Q_UNUSED(index)
return m_encoding;
return *m_items.at(index);
}
int SubDirFileIterator::maxProgress() const
......
......@@ -28,10 +28,10 @@
#include "utils_global.h"
#include <QDir>
#include <QFuture>
#include <QMap>
#include <QStack>
#include <QDir>
#include <QTextDocument>
QT_FORWARD_DECLARE_CLASS(QTextCodec)
......@@ -44,6 +44,7 @@ public:
class Item
{
public:
Item() : encoding(nullptr) { }
Item(const QString &path, QTextCodec *codec)
: filePath(path), encoding(codec)
{}
......@@ -62,11 +63,15 @@ public:
typedef const value_type *pointer;
typedef const value_type &reference;
const_iterator(const FileIterator *parent, Item item, int id)
: m_parent(parent), m_item(item), m_index(id)
const_iterator() : m_parent(nullptr), m_index(-1) { }
const_iterator(const FileIterator *parent, int id)
: m_parent(parent), m_index(id)
{}
const Item operator*() const { return m_item; }
const Item *operator->() const { return &m_item; }
const_iterator(const const_iterator &) = default;
const_iterator &operator=(const const_iterator &) = default;
reference operator*() const { return m_parent->itemAt(m_index); }
pointer operator->() const { return &m_parent->itemAt(m_index); }
void operator++() { m_parent->advance(this); }
bool operator==(const const_iterator &other) const
{
......@@ -75,23 +80,22 @@ public:
bool operator!=(const const_iterator &other) const { return !operator==(other); }
const FileIterator *m_parent;
Item m_item;
int m_index; // -1 == end
};
virtual ~FileIterator() {}
void advance(const_iterator *it) const;
const_iterator begin() const;
const_iterator end() const;
virtual int maxProgress() const = 0;
virtual int currentProgress() const = 0;
void advance(const_iterator *it) const;
virtual const Item &itemAt(int index) const = 0;
protected:
virtual void update(int requestedIndex) = 0;
virtual int currentFileCount() const = 0;
virtual QString fileAt(int index) const = 0;
virtual QTextCodec *codecAt(int index) const = 0;
};
class QTCREATOR_UTILS_EXPORT FileListIterator : public FileIterator
......@@ -106,13 +110,10 @@ public:
protected:
void update(int requestedIndex) override;
int currentFileCount() const override;
QString fileAt(int index) const override;
QTextCodec *codecAt(int index) const override;
const Item &itemAt(int index) const override;
private:
QTextCodec *encodingAt(int index) const;
QStringList m_files;
QList<QTextCodec *> m_encodings;
QVector<Item> m_items;
int m_maxIndex;
};
......@@ -121,6 +122,7 @@ class QTCREATOR_UTILS_EXPORT SubDirFileIterator : public FileIterator
public:
SubDirFileIterator(const QStringList &directories, const QStringList &filters,
QTextCodec *encoding = 0);
~SubDirFileIterator();
int maxProgress() const override;
int currentProgress() const override;
......@@ -128,8 +130,7 @@ public:
protected:
void update(int requestedIndex) override;
int currentFileCount() const override;
QString fileAt(int index) const override;
QTextCodec *codecAt(int index) const override;
const Item &itemAt(int index) const override;
private:
QStringList m_filters;
......@@ -138,7 +139,8 @@ private:
QStack<qreal> m_progressValues;
QStack<bool> m_processedValues;
qreal m_progress;
QStringList m_files;
// Use heap allocated objects directly because we want references to stay valid even after resize
QList<Item *> m_items;
};
class QTCREATOR_UTILS_EXPORT FileSearchResult
......
......@@ -53,6 +53,12 @@ struct functionTraits<Result(*)(Args...)> : public functionTraits<Result(Args...
{
};
// const function pointer
template <typename Result, typename... Args>
struct functionTraits<Result(* const)(Args...)> : public functionTraits<Result(Args...)>
{
};
// member function
template <typename Type, typename Result, typename... Args>
struct functionTraits<Result(Type::*)(Args...)> : public functionTraits<Result(Type&,Args...)>
......@@ -65,6 +71,18 @@ struct functionTraits<Result(Type::*)(Args...) const> : public functionTraits<Re
{
};
// const pointer to member function
template <typename Type, typename Result, typename... Args>
struct functionTraits<Result(Type::* const)(Args...)> : public functionTraits<Result(Type&,Args...)>
{
};
// const pointer to const member function
template <typename Type, typename Result, typename... Args>
struct functionTraits<Result(Type::* const)(Args...) const> : public functionTraits<Result(Type&,Args...)>
{
};
// TODO: enable lvalue and rvalue ref member function later (MSVC 2015?)
//// lvalue ref member function
//template <typename Type, typename Result, typename... Args>
......
......@@ -44,8 +44,13 @@ HeaderViewStretcher::HeaderViewStretcher(QHeaderView *headerView, int columnToSt
: QObject(headerView), m_columnToStretch(columnToStretch)
{
headerView->installEventFilter(this);
stretch();
}
void HeaderViewStretcher::stretch()
{
QHideEvent fake;
HeaderViewStretcher::eventFilter(headerView, &fake);
HeaderViewStretcher::eventFilter(parent(), &fake);
}
bool HeaderViewStretcher::eventFilter(QObject *obj, QEvent *ev)
......
......@@ -41,7 +41,8 @@ class QTCREATOR_UTILS_EXPORT HeaderViewStretcher : public QObject
public:
explicit HeaderViewStretcher(QHeaderView *headerView, int columnToStretch);
virtual bool eventFilter(QObject *obj, QEvent *ev);
void stretch();
bool eventFilter(QObject *obj, QEvent *ev) override;
};
} // namespace Utils
......
This diff is collapsed.
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef MULTITASK_H
#define MULTITASK_H
#include "utils_global.h"
#include "runextensions.h"
#include <QObject>
#include <QList>
#include <QEventLoop>
#include <QFutureWatcher>
#include <QtConcurrentRun>
#include <QThreadPool>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace QtConcurrent {
class QTCREATOR_UTILS_EXPORT MultiTaskBase : public QObject, public QRunnable
{
Q_OBJECT
protected slots:
virtual void cancelSelf() = 0;
virtual void setFinished() = 0;
virtual void setProgressRange(int min, int max) = 0;
virtual void setProgressValue(int value) = 0;
virtual void setProgressText(QString value) = 0;
};
template <typename Class, typename R>
class MultiTask : public MultiTaskBase
{
public:
MultiTask(void (Class::*fn)(QFutureInterface<R> &), const QList<Class *> &objects)
: fn(fn),
objects(objects)
{
maxProgress = 100*objects.size();
}
QFuture<R> future()
{
futureInterface.reportStarted();
return futureInterface.future();
}
void run()
{
QThreadPool::globalInstance()->releaseThread();
futureInterface.setProgressRange(0, maxProgress);
foreach (Class *object, objects) {
QFutureWatcher<R> *watcher = new QFutureWatcher<R>();
watchers.insert(object, watcher);
finished.insert(watcher, false);
connect(watcher, &QFutureWatcherBase::finished,
this, &MultiTask::setFinished);
connect(watcher, &QFutureWatcherBase::progressRangeChanged,
this, &MultiTask::setProgressRange);
connect(watcher, &QFutureWatcherBase::progressValueChanged,
this, &MultiTask::setProgressValue);
connect(watcher, &QFutureWatcherBase::progressTextChanged,
this, &MultiTask::setProgressText);
watcher->setFuture(Utils::runAsync(QThreadPool::globalInstance(), fn, object));
}
selfWatcher = new QFutureWatcher<R>();
connect(selfWatcher, &QFutureWatcherBase::canceled, this, &MultiTask::cancelSelf);
selfWatcher->setFuture(futureInterface.future());
loop = new QEventLoop;
loop->exec();
futureInterface.reportFinished();
QThreadPool::globalInstance()->reserveThread();
qDeleteAll(watchers);
delete selfWatcher;
delete loop;
}
protected:
void cancelSelf()
{
foreach (QFutureWatcher<R> *watcher, watchers)
watcher->future().cancel();
}
void setFinished()
{
updateProgress();
QFutureWatcher<R> *watcher = static_cast<QFutureWatcher<R> *>(sender());
if (finished.contains(watcher))
finished[watcher] = true;
bool allFinished = true;
foreach (bool isFinished, finished) {
if (!isFinished) {
allFinished = false;
break;
}
}
if (allFinished)
loop->quit();
}
void setProgressRange(int min, int max)
{
Q_UNUSED(min)
Q_UNUSED(max)
updateProgress();
}
void setProgressValue(int value)
{
Q_UNUSED(value)
updateProgress();
}
void setProgressText(QString value)
{
Q_UNUSED(value)
updateProgressText();
}
private:
void updateProgress()
{
int progressSum = 0;
foreach (QFutureWatcher<R> *watcher, watchers) {
if (watcher->progressMinimum() == watcher->progressMaximum()) {
if (watcher->future().isFinished() && !watcher->future().isCanceled())
progressSum += 100;
} else {
progressSum += 100*(watcher->progressValue()-watcher->progressMinimum())/(watcher->progressMaximum()-watcher->progressMinimum());
}
}
futureInterface.setProgressValue(progressSum);
}
void updateProgressText()
{
QString text;
foreach (QFutureWatcher<R> *watcher, watchers) {
if (!watcher->progressText().isEmpty()) {
text += watcher->progressText();
text += QLatin1Char('\n');
}
}
text = text.trimmed();
futureInterface.setProgressValueAndText(futureInterface.progressValue(), text);
}
QFutureInterface<R> futureInterface;
void (Class::*fn)(QFutureInterface<R> &);
QList<Class *> objects;
QFutureWatcher<R> *selfWatcher;
QMap<Class *, QFutureWatcher<R> *> watchers;
QMap<QFutureWatcher<R> *, bool> finished;
QEventLoop *loop;
int maxProgress;
};
template <typename Class, typename T>
QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &), const QList<Class *> &objects, int priority = 0)
{
MultiTask<Class, T> *task = new MultiTask<Class, T>(fn, objects);
QFuture<T> future = task->future();
QThreadPool::globalInstance()->start(task, priority);
return future;
}
} // namespace QtConcurrent
QT_END_NAMESPACE
#endif // MULTITASK_H
......@@ -66,6 +66,9 @@ QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title,
msg.setText(prompt);
msg.setDetailedText(details);
msg.button(QMessageBox::Close)->setText(QCoreApplication::translate("Utils::reloadPrompt",
"&Close"));
switch (msg.exec()) {
case QMessageBox::Yes:
return ReloadCurrent;
......
......@@ -168,8 +168,6 @@ struct resultType<Function &&> : public resultType<Function>
{
};
// work around bug in MSVC 2015 where a reference_wrapper has a call operator even if the wrapped
// object doesn't
template <typename Function>
struct resultType<std::reference_wrapper<Function>> : public resultType<Function>
{
......@@ -282,7 +280,7 @@ template <typename ResultType, typename Function, typename... Args,
typename = typename std::enable_if<
!std::is_member_pointer<typename std::decay<Function>::type>::value
>::type>
void runAsyncImpl(QFutureInterface<ResultType> futureInterface, Function &&function, Args&&... args)
void runAsyncMemberDispatch(QFutureInterface<ResultType> futureInterface, Function &&function, Args&&... args)
{
runAsyncArityDispatch(std::integral_constant<bool, (functionTraits<Function>::arity > 0)>(),
futureInterface, std::forward<Function>(function), std::forward<Args>(args)...);
......@@ -293,14 +291,30 @@ template <typename ResultType, typename Function, typename Obj, typename... Args
typename = typename std::enable_if<
std::is_member_pointer<typename std::decay<Function>::type>::value
>::type>
void runAsyncImpl(QFutureInterface<ResultType> futureInterface, Function &&function, Obj &&obj, Args&&... args)
void runAsyncMemberDispatch(QFutureInterface<ResultType> futureInterface, Function &&function, Obj &&obj, Args&&... args)
{
// Wrap member function with object into callable
runAsyncImpl(futureInterface,
MemberCallable<Function>(std::forward<Function>(function), std::forward<Obj>(obj)),
MemberCallable<typename std::decay<Function>::type>(std::forward<Function>(function), std::forward<Obj>(obj)),
std::forward<Args>(args)...);
}
// cref to function/callable
template <typename ResultType, typename Function, typename... Args>
void runAsyncImpl(QFutureInterface<ResultType> futureInterface,
std::reference_wrapper<Function> functionWrapper, Args&&... args)
{
runAsyncMemberDispatch(futureInterface, functionWrapper.get(), std::forward<Args>(args)...);
}
// function/callable, no cref
template <typename ResultType, typename Function, typename... Args>
void runAsyncImpl(QFutureInterface<ResultType> futureInterface,
Function &&function, Args&&... args)
{
runAsyncMemberDispatch(futureInterface, std::forward<Function>(function),
std::forward<Args>(args)...);
}
/*
AsyncJob is a QRunnable that wraps a function with the
arguments that are passed to it when it is run in a thread.
......
......@@ -673,23 +673,15 @@ bool operator==(Type first, const SmallString& second) noexcept
inline
bool operator==(const SmallString& first, const SmallString& second) noexcept
{
if (Q_LIKELY(first.size() != second.size()))
return false;
const int comparison = std::memcmp(first.data(), second.data(), first.size());