aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/utils')
-rw-r--r--src/libs/utils/algorithm.h2
-rw-r--r--src/libs/utils/basetreeview.cpp96
-rw-r--r--src/libs/utils/basetreeview.h3
-rw-r--r--src/libs/utils/checkablemessagebox.cpp115
-rw-r--r--src/libs/utils/checkablemessagebox.h10
-rw-r--r--src/libs/utils/elfreader.cpp2
-rw-r--r--src/libs/utils/fadingindicator.cpp146
-rw-r--r--src/libs/utils/fadingindicator.h (renamed from src/libs/utils/iwelcomepage.cpp)23
-rw-r--r--src/libs/utils/fancymainwindow.cpp11
-rw-r--r--src/libs/utils/fileinprojectfinder.cpp66
-rw-r--r--src/libs/utils/fileinprojectfinder.h4
-rw-r--r--src/libs/utils/fileutils.cpp57
-rw-r--r--src/libs/utils/fileutils.h14
-rw-r--r--src/libs/utils/images/progressindicator_big.pngbin0 -> 1443 bytes
-rw-r--r--src/libs/utils/images/progressindicator_big@2x.pngbin0 -> 2449 bytes
-rw-r--r--src/libs/utils/images/progressindicator_medium.pngbin0 -> 875 bytes
-rw-r--r--src/libs/utils/images/progressindicator_medium@2x.pngbin0 -> 1541 bytes
-rw-r--r--src/libs/utils/images/progressindicator_small.pngbin0 -> 305 bytes
-rw-r--r--src/libs/utils/images/progressindicator_small@2x.pngbin0 -> 397 bytes
-rw-r--r--src/libs/utils/iwelcomepage.h74
-rw-r--r--src/libs/utils/macroexpander.cpp2
-rw-r--r--src/libs/utils/outputformatter.cpp11
-rw-r--r--src/libs/utils/outputformatter.h2
-rw-r--r--src/libs/utils/persistentsettings.cpp4
-rw-r--r--src/libs/utils/persistentsettings.h2
-rw-r--r--src/libs/utils/portlist.cpp2
-rw-r--r--src/libs/utils/progressindicator.cpp140
-rw-r--r--src/libs/utils/progressindicator.h82
-rw-r--r--src/libs/utils/projectintropage.cpp6
-rw-r--r--src/libs/utils/reloadpromptutils.cpp7
-rw-r--r--src/libs/utils/reloadpromptutils.h3
-rw-r--r--src/libs/utils/synchronousprocess.cpp2
-rw-r--r--src/libs/utils/theme/theme.cpp2
-rw-r--r--src/libs/utils/tooltip/tipcontents.cpp196
-rw-r--r--src/libs/utils/tooltip/tipcontents.h130
-rw-r--r--src/libs/utils/tooltip/tips.cpp127
-rw-r--r--src/libs/utils/tooltip/tips.h74
-rw-r--r--src/libs/utils/tooltip/tooltip.cpp96
-rw-r--r--src/libs/utils/tooltip/tooltip.h31
-rw-r--r--src/libs/utils/treemodel.cpp926
-rw-r--r--src/libs/utils/treemodel.h224
-rw-r--r--src/libs/utils/unixutils.cpp5
-rw-r--r--src/libs/utils/utils-lib.pri12
-rw-r--r--src/libs/utils/utils.qbs12
-rw-r--r--src/libs/utils/utils.qrc6
-rw-r--r--src/libs/utils/wizard.cpp6
-rw-r--r--src/libs/utils/wizardpage.h4
47 files changed, 2003 insertions, 734 deletions
diff --git a/src/libs/utils/algorithm.h b/src/libs/utils/algorithm.h
index 5d79c6f2d47..0fb7a35a418 100644
--- a/src/libs/utils/algorithm.h
+++ b/src/libs/utils/algorithm.h
@@ -324,7 +324,7 @@ template<template<typename> class C, // result container type
typename R,
typename S>
Q_REQUIRED_RESULT
-auto transform(const SC &container, R (S::*p)())
+auto transform(const SC &container, R (S::*p)() const)
-> C<typename RemoveCvAndReference<R>::type>
{
return TransformImpl<
diff --git a/src/libs/utils/basetreeview.cpp b/src/libs/utils/basetreeview.cpp
index a6af74a9e4e..f87a7ba7f02 100644
--- a/src/libs/utils/basetreeview.cpp
+++ b/src/libs/utils/basetreeview.cpp
@@ -30,6 +30,8 @@
#include "basetreeview.h"
+#include "progressindicator.h"
+
#include <utils/qtcassert.h>
#include <QDebug>
@@ -54,7 +56,7 @@ class BaseTreeViewPrivate : public QObject
public:
explicit BaseTreeViewPrivate(BaseTreeView *parent)
- : q(parent), m_settings(0), m_expectUserChanges(false)
+ : q(parent), m_settings(0), m_expectUserChanges(false), m_progressIndicator(0)
{}
bool eventFilter(QObject *, QEvent *event)
@@ -122,7 +124,7 @@ public:
}
}
- Q_SLOT void handleSectionResized(int logicalIndex, int /*oldSize*/, int newSize)
+ void handleSectionResized(int logicalIndex, int /*oldSize*/, int newSize)
{
if (m_expectUserChanges) {
m_userHandled[logicalIndex] = newSize;
@@ -157,7 +159,7 @@ public:
return minimum;
}
- Q_SLOT void resizeColumns()
+ Q_SLOT void resizeColumns() // Needs moc, see BaseTreeView::setModel
{
QHeaderView *h = q->header();
QTC_ASSERT(h, return);
@@ -176,17 +178,7 @@ public:
}
}
- Q_SLOT void rowActivatedHelper(const QModelIndex &index)
- {
- q->rowActivated(index);
- }
-
- Q_SLOT void rowClickedHelper(const QModelIndex &index)
- {
- q->rowClicked(index);
- }
-
- Q_SLOT void toggleColumnWidth(int logicalIndex)
+ void toggleColumnWidth(int logicalIndex)
{
QHeaderView *h = q->header();
const int currentSize = h->sectionSize(logicalIndex);
@@ -211,6 +203,7 @@ public:
QSettings *m_settings;
QString m_settingsKey;
bool m_expectUserChanges;
+ ProgressIndicator *m_progressIndicator;
};
class BaseTreeViewDelegate : public QItemDelegate
@@ -251,14 +244,15 @@ BaseTreeView::BaseTreeView(QWidget *parent)
h->setSectionsClickable(true);
h->viewport()->installEventFilter(d);
- connect(this, SIGNAL(activated(QModelIndex)),
- d, SLOT(rowActivatedHelper(QModelIndex)));
- connect(this, SIGNAL(clicked(QModelIndex)),
- d, SLOT(rowClickedHelper(QModelIndex)));
- connect(h, SIGNAL(sectionClicked(int)),
- d, SLOT(toggleColumnWidth(int)));
- connect(h, SIGNAL(sectionResized(int,int,int)),
- d, SLOT(handleSectionResized(int,int,int)));
+ connect(this, &QAbstractItemView::activated,
+ this, &BaseTreeView::rowActivated);
+ connect(this, &QAbstractItemView::clicked,
+ this, &BaseTreeView::rowClicked);
+
+ connect(h, &QHeaderView::sectionClicked,
+ d, &BaseTreeViewPrivate::toggleColumnWidth);
+ connect(h, &QHeaderView::sectionResized,
+ d, &BaseTreeViewPrivate::handleSectionResized);
}
BaseTreeView::~BaseTreeView()
@@ -268,18 +262,36 @@ BaseTreeView::~BaseTreeView()
void BaseTreeView::setModel(QAbstractItemModel *m)
{
+ struct ExtraConnection {
+ const char *signature;
+ const char *qsignal;
+ QObject *receiver;
+ const char *qslot;
+ };
+#define DESC(sign, receiver, slot) { #sign, SIGNAL(sign), receiver, SLOT(slot) }
+ const ExtraConnection c[] = {
+ DESC(columnAdjustmentRequested(), d, resizeColumns()),
+ DESC(requestExpansion(QModelIndex), this, expand(QModelIndex))
+ };
+#undef DESC
+
QAbstractItemModel *oldModel = model();
- const char *sig = "columnAdjustmentRequested()";
if (oldModel) {
- int index = model()->metaObject()->indexOfSignal(sig);
- if (index != -1)
- disconnect(model(), SIGNAL(columnAdjustmentRequested()), d, SLOT(resizeColumns()));
+ for (unsigned i = 0; i < sizeof(c) / sizeof(c[0]); ++i) {
+ int index = model()->metaObject()->indexOfSignal(c[i].signature);
+ if (index != -1)
+ disconnect(model(), c[i].qsignal, c[i].receiver, c[i].qslot);
+ }
}
+
TreeView::setModel(m);
+
if (m) {
- int index = m->metaObject()->indexOfSignal(sig);
- if (index != -1)
- connect(m, SIGNAL(columnAdjustmentRequested()), d, SLOT(resizeColumns()));
+ for (unsigned i = 0; i < sizeof(c) / sizeof(c[0]); ++i) {
+ int index = m->metaObject()->indexOfSignal(c[i].signature);
+ if (index != -1)
+ connect(model(), c[i].qsignal, c[i].receiver, c[i].qslot);
+ }
d->restoreState();
}
}
@@ -292,6 +304,32 @@ void BaseTreeView::mousePressEvent(QMouseEvent *ev)
d->toggleColumnWidth(columnAt(ev->x()));
}
+/*!
+ Shows a round spinning progress indicator on top of the tree view.
+ Creates a progress indicator widget if necessary.
+ \sa hideProgressIndicator()
+ */
+void BaseTreeView::showProgressIndicator()
+{
+ if (!d->m_progressIndicator) {
+ d->m_progressIndicator = new ProgressIndicator(ProgressIndicator::Large);
+ d->m_progressIndicator->attachToWidget(this);
+ }
+ d->m_progressIndicator->show();
+}
+
+/*!
+ Hides the round spinning progress indicator that was shown with
+ BaseTreeView::showProgressIndicator(). Note that the progress indicator widget is not
+ destroyed.
+ \sa showProgressIndicator()
+ */
+void BaseTreeView::hideProgressIndicator()
+{
+ QTC_ASSERT(d->m_progressIndicator, return);
+ d->m_progressIndicator->hide();
+}
+
void BaseTreeView::setSettings(QSettings *settings, const QByteArray &key)
{
QTC_ASSERT(!d->m_settings, qDebug() << "DUPLICATED setSettings" << key);
diff --git a/src/libs/utils/basetreeview.h b/src/libs/utils/basetreeview.h
index cde60b92889..777f1f51291 100644
--- a/src/libs/utils/basetreeview.h
+++ b/src/libs/utils/basetreeview.h
@@ -59,6 +59,9 @@ public:
virtual void rowClicked(const QModelIndex &) {}
void mousePressEvent(QMouseEvent *ev);
+ void showProgressIndicator();
+ void hideProgressIndicator();
+
public slots:
void setAlternatingRowColorsHelper(bool on) { setAlternatingRowColors(on); }
diff --git a/src/libs/utils/checkablemessagebox.cpp b/src/libs/utils/checkablemessagebox.cpp
index 28e88183941..2a5126c030c 100644
--- a/src/libs/utils/checkablemessagebox.cpp
+++ b/src/libs/utils/checkablemessagebox.cpp
@@ -288,6 +288,49 @@ QMessageBox::StandardButton CheckableMessageBox::dialogButtonBoxToMessageBoxButt
return static_cast<QMessageBox::StandardButton>(int(db));
}
+bool askAgain(QSettings *settings, const QString &settingsSubKey)
+{
+ QTC_CHECK(settings);
+ if (settings) {
+ settings->beginGroup(QLatin1String(kDoNotAskAgainKey));
+ bool shouldNotAsk = settings->value(settingsSubKey, false).toBool();
+ settings->endGroup();
+ if (shouldNotAsk)
+ return false;
+ }
+ return true;
+}
+
+enum DoNotAskAgainType{Question, Information};
+
+void initDoNotAskAgainMessageBox(CheckableMessageBox &messageBox, const QString &title,
+ const QString &text, QDialogButtonBox::StandardButtons buttons,
+ QDialogButtonBox::StandardButton defaultButton,
+ DoNotAskAgainType type)
+{
+ messageBox.setWindowTitle(title);
+ messageBox.setIconPixmap(QMessageBox::standardIcon(type == Information
+ ? QMessageBox::Information
+ : QMessageBox::Question));
+ messageBox.setText(text);
+ messageBox.setCheckBoxVisible(true);
+ messageBox.setCheckBoxText(type == Information ? CheckableMessageBox::msgDoNotShowAgain()
+ : CheckableMessageBox::msgDoNotAskAgain());
+ messageBox.setChecked(false);
+ messageBox.setStandardButtons(buttons);
+ messageBox.setDefaultButton(defaultButton);
+}
+
+void doNotAskAgain(QSettings *settings, const QString &settingsSubKey)
+{
+ if (!settings)
+ return;
+
+ settings->beginGroup(QLatin1String(kDoNotAskAgainKey));
+ settings->setValue(settingsSubKey, true);
+ settings->endGroup();
+}
+
/*!
Shows a message box with given \a title and \a text, and a \gui {Do not ask again} check box.
If the user checks the check box and accepts the dialog with the \a acceptButton,
@@ -306,35 +349,44 @@ CheckableMessageBox::doNotAskAgainQuestion(QWidget *parent, const QString &title
QDialogButtonBox::StandardButton acceptButton)
{
- QTC_CHECK(settings);
- if (settings) {
- settings->beginGroup(QLatin1String(kDoNotAskAgainKey));
- bool shouldNotAsk = settings->value(settingsSubKey, false).toBool();
- settings->endGroup();
- if (shouldNotAsk)
- return acceptButton;
- }
+ if (!askAgain(settings, settingsSubKey))
+ return acceptButton;
- CheckableMessageBox mb(parent);
- mb.setWindowTitle(title);
- mb.setIconPixmap(QMessageBox::standardIcon(QMessageBox::Question));
- mb.setText(text);
- mb.setCheckBoxVisible(true);
- mb.setCheckBoxText(CheckableMessageBox::msgDoNotAskAgain());
- mb.setChecked(false);
- mb.setStandardButtons(buttons);
- mb.setDefaultButton(defaultButton);
- mb.exec();
+ CheckableMessageBox messageBox(parent);
+ initDoNotAskAgainMessageBox(messageBox, title, text, buttons, defaultButton, Question);
+ messageBox.exec();
+ if (messageBox.isChecked() && (messageBox.clickedStandardButton() == acceptButton))
+ doNotAskAgain(settings, settingsSubKey);
- if (settings) {
- settings->beginGroup(QLatin1String(kDoNotAskAgainKey));
- if (mb.isChecked() && (mb.clickedStandardButton() == acceptButton))
- settings->setValue(settingsSubKey, true);
- else // clean up doesn't hurt
- settings->remove(settingsSubKey);
- settings->endGroup();
- }
- return mb.clickedStandardButton();
+ return messageBox.clickedStandardButton();
+}
+
+/*!
+ Shows a message box with given \a title and \a text, and a \gui {Do not show again} check box.
+ If the user checks the check box and quits the dialog, further invocations of this
+ function with the same \a settings and \a settingsSubKey will not show the dialog, but instantly return.
+
+ Returns the clicked button, or QDialogButtonBox::NoButton if the user rejects the dialog
+ with the escape key, or \a defaultButton if the dialog is suppressed.
+*/
+QDialogButtonBox::StandardButton
+CheckableMessageBox::doNotShowAgainInformation(QWidget *parent, const QString &title,
+ const QString &text, QSettings *settings,
+ const QString &settingsSubKey,
+ QDialogButtonBox::StandardButtons buttons,
+ QDialogButtonBox::StandardButton defaultButton)
+
+{
+ if (!askAgain(settings, settingsSubKey))
+ return defaultButton;
+
+ CheckableMessageBox messageBox(parent);
+ initDoNotAskAgainMessageBox(messageBox, title, text, buttons, defaultButton, Information);
+ messageBox.exec();
+ if (messageBox.isChecked())
+ doNotAskAgain(settings, settingsSubKey);
+
+ return messageBox.clickedStandardButton();
}
/*!
@@ -377,4 +429,13 @@ QString CheckableMessageBox::msgDoNotAskAgain()
return QApplication::translate("Utils::CheckableMessageBox", "Do not &ask again");
}
+/*!
+ Returns the standard \gui {Do not show again} check box text.
+ \sa doNotShowAgainInformation()
+*/
+QString CheckableMessageBox::msgDoNotShowAgain()
+{
+ return QApplication::translate("Utils::CheckableMessageBox", "Do not &show again");
+}
+
} // namespace Utils
diff --git a/src/libs/utils/checkablemessagebox.h b/src/libs/utils/checkablemessagebox.h
index 3c0e241659b..894d955a64f 100644
--- a/src/libs/utils/checkablemessagebox.h
+++ b/src/libs/utils/checkablemessagebox.h
@@ -86,6 +86,15 @@ public:
QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No,
QDialogButtonBox::StandardButton acceptButton = QDialogButtonBox::Yes);
+ static QDialogButtonBox::StandardButton
+ doNotShowAgainInformation(QWidget *parent,
+ const QString &title,
+ const QString &text,
+ QSettings *settings,
+ const QString &settingsSubKey,
+ QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Ok,
+ QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::NoButton);
+
QString text() const;
void setText(const QString &);
@@ -119,6 +128,7 @@ public:
static void resetAllDoNotAskAgainQuestions(QSettings *settings);
static bool hasSuppressedQuestions(QSettings *settings);
static QString msgDoNotAskAgain();
+ static QString msgDoNotShowAgain();
private slots:
void slotClicked(QAbstractButton *b);
diff --git a/src/libs/utils/elfreader.cpp b/src/libs/utils/elfreader.cpp
index 29f33d19cfe..bc34ca3622a 100644
--- a/src/libs/utils/elfreader.cpp
+++ b/src/libs/utils/elfreader.cpp
@@ -117,7 +117,7 @@ bool ElfMapper::map()
// Try reading the data into memory instead.
try {
raw = file.readAll();
- } catch (std::bad_alloc &) {
+ } catch (const std::bad_alloc &) {
return false;
}
start = raw.constData();
diff --git a/src/libs/utils/fadingindicator.cpp b/src/libs/utils/fadingindicator.cpp
new file mode 100644
index 00000000000..ee8c2c70b3a
--- /dev/null
+++ b/src/libs/utils/fadingindicator.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "fadingindicator.h"
+
+#include "stylehelper.h"
+
+#include <QGraphicsOpacityEffect>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPainter>
+#include <QPixmap>
+#include <QPropertyAnimation>
+#include <QTimer>
+
+namespace Utils {
+namespace Internal {
+
+class FadingIndicatorPrivate : public QWidget
+{
+ Q_OBJECT
+
+public:
+ FadingIndicatorPrivate(QWidget *parent = 0)
+ : QWidget(parent)
+ {
+ m_effect = new QGraphicsOpacityEffect(this);
+ setGraphicsEffect(m_effect);
+ m_effect->setOpacity(1.);
+
+ m_label = new QLabel;
+ QFont font = m_label->font();
+ font.setPixelSize(45);
+ m_label->setFont(font);
+ QPalette pal = palette();
+ pal.setColor(QPalette::Foreground, pal.color(QPalette::Background));
+ m_label->setPalette(pal);
+ auto layout = new QHBoxLayout;
+ setLayout(layout);
+ layout->addWidget(m_label);
+ }
+
+ void setText(const QString &text)
+ {
+ m_pixmap = QPixmap();
+ m_label->setText(text);
+ adjustSize();
+ if (QWidget *parent = parentWidget())
+ move(parent->rect().center() - rect().center());
+ }
+
+ void setPixmap(const QString &uri)
+ {
+ m_label->hide();
+ m_pixmap.load(Utils::StyleHelper::dpiSpecificImageFile(uri));
+ resize(m_pixmap.size() / m_pixmap.devicePixelRatio());
+ if (QWidget *parent = parentWidget())
+ move(parent->rect().center() - rect().center());
+ }
+
+ void run(int ms)
+ {
+ show();
+ raise();
+ QTimer::singleShot(ms, this, SLOT(runInternal()));
+ }
+
+protected:
+ void paintEvent(QPaintEvent *)
+ {
+ QPainter p(this);
+ p.setRenderHint(QPainter::Antialiasing);
+ if (!m_pixmap.isNull()) {
+ p.drawPixmap(rect(), m_pixmap);
+ } else {
+ p.setBrush(palette().color(QPalette::Foreground));
+ p.setPen(Qt::NoPen);
+ p.drawRoundedRect(rect(), 15, 15);
+ }
+ }
+
+private slots:
+ void runInternal()
+ {
+ QPropertyAnimation *anim = new QPropertyAnimation(m_effect, "opacity", this);
+ anim->setDuration(200);
+ anim->setEndValue(0.);
+ connect(anim, SIGNAL(finished()), this, SLOT(deleteLater()));
+ anim->start(QAbstractAnimation::DeleteWhenStopped);
+ }
+
+private:
+ QGraphicsOpacityEffect *m_effect;
+ QLabel *m_label;
+ QPixmap m_pixmap;
+};
+
+} // Internal
+
+namespace FadingIndicator {
+
+void showText(QWidget *parent, const QString &text)
+{
+ auto indicator = new Internal::FadingIndicatorPrivate(parent);
+ indicator->setText(text);
+ indicator->run(1000); // deletes itself
+}
+
+void showPixmap(QWidget *parent, const QString &pixmap)
+{
+ auto indicator = new Internal::FadingIndicatorPrivate(parent);
+ indicator->setPixmap(pixmap);
+ indicator->run(300); // deletes itself
+}
+
+} // FadingIndicator
+} // Utils
+
+#include "fadingindicator.moc"
diff --git a/src/libs/utils/iwelcomepage.cpp b/src/libs/utils/fadingindicator.h
index c5b781fe918..7738e751a64 100644
--- a/src/libs/utils/iwelcomepage.cpp
+++ b/src/libs/utils/fadingindicator.h
@@ -28,20 +28,23 @@
**
****************************************************************************/
-#include "iwelcomepage.h"
-#include <QUrl>
+#ifndef FADINGINDICATOR_H
+#define FADINGINDICATOR_H
+
+#include "utils_global.h"
+
+#include <QString>
+#include <QWidget>
namespace Utils {
+namespace FadingIndicator {
-IWelcomePage::IWelcomePage()
-{
-}
+QTCREATOR_UTILS_EXPORT void showText(QWidget *parent, const QString &text);
+QTCREATOR_UTILS_EXPORT void showPixmap(QWidget *parent, const QString &pixmap);
-IWelcomePage::~IWelcomePage()
-{
-}
+} // FadingIndicator
+} // Utils
-} // namespace Utils
+#endif // FADINGINDICATOR_H
-#include "moc_iwelcomepage.cpp"
diff --git a/src/libs/utils/fancymainwindow.cpp b/src/libs/utils/fancymainwindow.cpp
index 3699e3af55f..097771a2c22 100644
--- a/src/libs/utils/fancymainwindow.cpp
+++ b/src/libs/utils/fancymainwindow.cpp
@@ -199,13 +199,6 @@ public:
QWidget::enterEvent(event);
}
- void leaveEvent(QEvent *event)
- {
- if (!q->isFloating())
- setActive(false);
- QWidget::leaveEvent(event);
- }
-
void setActive(bool on)
{
m_active = on;
@@ -311,6 +304,10 @@ void DockWidget::enterEvent(QEvent *event)
void DockWidget::leaveEvent(QEvent *event)
{
+ if (!isFloating()) {
+ m_timer.stop();
+ m_titleBar->setActive(false);
+ }
QApplication::instance()->removeEventFilter(this);
QDockWidget::leaveEvent(event);
}
diff --git a/src/libs/utils/fileinprojectfinder.cpp b/src/libs/utils/fileinprojectfinder.cpp
index 41110fceb2d..e40b33136b7 100644
--- a/src/libs/utils/fileinprojectfinder.cpp
+++ b/src/libs/utils/fileinprojectfinder.cpp
@@ -29,12 +29,15 @@
****************************************************************************/
#include "fileinprojectfinder.h"
-#include <utils/qtcassert.h>
+#include "fileutils.h"
+#include "qtcassert.h"
#include <QDebug>
#include <QFileInfo>
#include <QUrl>
+#include <algorithm>
+
enum { debug = false };
namespace Utils {
@@ -211,20 +214,19 @@ QString FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const
}
}
- // find (solely by filename) in project files
+ // find best matching file path in project files
if (debug)
qDebug() << "FileInProjectFinder: checking project files ...";
- const QString fileName = QFileInfo(originalPath).fileName();
- foreach (const QString &f, m_projectFiles) {
- if (QFileInfo(f).fileName() == fileName) {
- m_cache.insert(originalPath, f);
- if (success)
- *success = true;
- if (debug)
- qDebug() << "FileInProjectFinder: found" << f << "in project files";
- return f;
- }
+ const QString matchedFilePath
+ = bestMatch(
+ filesWithSameFileName(FileName::fromString(originalPath).fileName()),
+ originalPath);
+ if (!matchedFilePath.isEmpty()) {
+ m_cache.insert(originalPath, matchedFilePath);
+ if (success)
+ *success = true;
+ return matchedFilePath;
}
if (debug)
@@ -251,4 +253,44 @@ QString FileInProjectFinder::findFile(const QUrl &fileUrl, bool *success) const
return originalPath;
}
+QStringList FileInProjectFinder::filesWithSameFileName(const QString &fileName) const
+{
+ QStringList result;
+ foreach (const QString &f, m_projectFiles) {
+ if (FileName::fromString(f).fileName() == fileName)
+ result << f;
+ }
+ return result;
+}
+
+int FileInProjectFinder::rankFilePath(const QString &candidatePath, const QString &filePathToFind)
+{
+ int rank = 0;
+ for (int a = candidatePath.length(), b = filePathToFind.length();
+ --a >= 0 && --b >= 0 && candidatePath.at(a) == filePathToFind.at(b);)
+ rank++;
+ return rank;
+}
+
+QString FileInProjectFinder::bestMatch(const QStringList &filePaths, const QString &filePathToFind)
+{
+ if (filePaths.isEmpty())
+ return QString();
+ if (filePaths.length() == 1) {
+ if (debug)
+ qDebug() << "FileInProjectFinder: found" << filePaths.first() << "in project files";
+ return filePaths.first();
+ }
+ auto it = std::max_element(filePaths.constBegin(), filePaths.constEnd(),
+ [&filePathToFind] (const QString &a, const QString &b) -> bool {
+ return rankFilePath(a, filePathToFind) < rankFilePath(b, filePathToFind);
+ });
+ if (it != filePaths.cend()) {
+ if (debug)
+ qDebug() << "FileInProjectFinder: found best match" << *it << "in project files";
+ return *it;
+ }
+ return QString();
+}
+
} // namespace Utils
diff --git a/src/libs/utils/fileinprojectfinder.h b/src/libs/utils/fileinprojectfinder.h
index 253c747da58..c208ba2ecfd 100644
--- a/src/libs/utils/fileinprojectfinder.h
+++ b/src/libs/utils/fileinprojectfinder.h
@@ -54,6 +54,10 @@ public:
QString findFile(const QUrl &fileUrl, bool *success = 0) const;
private:
+ QStringList filesWithSameFileName(const QString &fileName) const;
+ static int rankFilePath(const QString &candidatePath, const QString &filePathToFind);
+ static QString bestMatch(const QStringList &filePaths, const QString &filePathToFind);
+
QString m_projectDir;
QString m_sysroot;
QStringList m_projectFiles;
diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp
index 78c8809a282..2c8baf56249 100644
--- a/src/libs/utils/fileutils.cpp
+++ b/src/libs/utils/fileutils.cpp
@@ -156,7 +156,7 @@ bool FileUtils::copyRecursively(const FileName &srcFilePath, const FileName &tgt
if (!tgtFilePath.exists()) {
QDir targetDir(tgtFilePath.toString());
targetDir.cdUp();
- if (!targetDir.mkdir(tgtFilePath.toFileInfo().fileName())) {
+ if (!targetDir.mkdir(tgtFilePath.fileName())) {
if (error) {
*error = QCoreApplication::translate("Utils::FileUtils", "Failed to create directory \"%1\".")
.arg(tgtFilePath.toUserOutput());
@@ -560,6 +560,30 @@ QString FileName::toUserOutput() const
return QDir::toNativeSeparators(toString());
}
+QString FileName::fileName(int pathComponents) const
+{
+ if (pathComponents < 0)
+ return *this;
+ const QChar slash = QLatin1Char('/');
+ QTC_CHECK(!endsWith(slash));
+ int i = lastIndexOf(slash);
+ if (pathComponents == 0 || i == -1)
+ return mid(i + 1);
+ int component = i + 1;
+ // skip adjacent slashes
+ while (i > 0 && at(--i) == slash);
+ while (i >= 0 && --pathComponents >= 0) {
+ i = lastIndexOf(slash, i);
+ component = i + 1;
+ while (i > 0 && at(--i) == slash);
+ }
+
+ // If there are no more slashes before the found one, return the entire string
+ if (i > 0 && lastIndexOf(slash, i) != -1)
+ return mid(component);
+ return *this;
+}
+
/// \returns a bool indicating whether a file with this
/// FileName exists.
bool FileName::exists() const
@@ -633,6 +657,13 @@ FileName FileName::fromUserInput(const QString &filename)
return FileName(clean);
}
+/// Constructs a FileName from \a fileName, which is encoded as UTF-8.
+/// \a fileName is not checked for validity.
+FileName FileName::fromUtf8(const char *filename, int filenameSize)
+{
+ return FileName(QString::fromUtf8(filename, filenameSize));
+}
+
FileName::FileName(const QString &string)
: QString(string)
{
@@ -730,6 +761,30 @@ FileName &FileName::appendString(QChar str)
return *this;
}
+QTextStream &operator<<(QTextStream &s, const FileName &fn)
+{
+ return s << fn.toString();
+}
+
+int FileNameList::removeDuplicates()
+{
+ QSet<FileName> seen;
+ int removed = 0;
+
+ for (int i = 0; i < size(); ) {
+ const FileName &fn = at(i);
+ if (seen.contains(fn)) {
+ removeAt(i);
+ ++removed;
+ } else {
+ seen.insert(fn);
+ ++i;
+ }
+ }
+
+ return removed;
+}
+
static bool isFileDrop(const QMimeData *d, QList<FileDropSupport::FileSpec> *files = 0)
{
// internal drop
diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h
index 3ddad1697e6..1ffea746a70 100644
--- a/src/libs/utils/fileutils.h
+++ b/src/libs/utils/fileutils.h
@@ -70,8 +70,10 @@ public:
static FileName fromString(const QString &filename, const QString &defaultExtension);
static FileName fromLatin1(const QByteArray &filename);
static FileName fromUserInput(const QString &filename);
+ static FileName fromUtf8(const char *filename, int filenameSize = -1);
QString toString() const;
QString toUserOutput() const;
+ QString fileName(int pathComponents = 0) const;
bool exists() const;
FileName parentDir() const;
@@ -102,6 +104,18 @@ private:
FileName(const QString &string);
};
+QTCREATOR_UTILS_EXPORT QTextStream &operator<<(QTextStream &s, const FileName &fn);
+
+class QTCREATOR_UTILS_EXPORT FileNameList : public QList<FileName>
+{
+public:
+ inline FileNameList() { }
+ inline explicit FileNameList(const FileName &i) { append(i); }
+ inline FileNameList(const FileNameList &l) : QList<FileName>(l) { }
+ inline FileNameList(const QList<FileName> &l) : QList<FileName>(l) { }
+
+ int removeDuplicates();
+};
class QTCREATOR_UTILS_EXPORT FileUtils {
public:
diff --git a/src/libs/utils/images/progressindicator_big.png b/src/libs/utils/images/progressindicator_big.png
new file mode 100644
index 00000000000..ac854f1e25e
--- /dev/null
+++ b/src/libs/utils/images/progressindicator_big.png
Binary files differ
diff --git a/src/libs/utils/images/progressindicator_big@2x.png b/src/libs/utils/images/progressindicator_big@2x.png
new file mode 100644
index 00000000000..23b488f23ab
--- /dev/null
+++ b/src/libs/utils/images/progressindicator_big@2x.png
Binary files differ
diff --git a/src/libs/utils/images/progressindicator_medium.png b/src/libs/utils/images/progressindicator_medium.png
new file mode 100644
index 00000000000..496f6880f2e
--- /dev/null
+++ b/src/libs/utils/images/progressindicator_medium.png
Binary files differ
diff --git a/src/libs/utils/images/progressindicator_medium@2x.png b/src/libs/utils/images/progressindicator_medium@2x.png
new file mode 100644
index 00000000000..c396d400128
--- /dev/null
+++ b/src/libs/utils/images/progressindicator_medium@2x.png
Binary files differ
diff --git a/src/libs/utils/images/progressindicator_small.png b/src/libs/utils/images/progressindicator_small.png
new file mode 100644
index 00000000000..8ba536403d8
--- /dev/null
+++ b/src/libs/utils/images/progressindicator_small.png
Binary files differ
diff --git a/src/libs/utils/images/progressindicator_small@2x.png b/src/libs/utils/images/progressindicator_small@2x.png
new file mode 100644
index 00000000000..e6dc7cc62d1
--- /dev/null
+++ b/src/libs/utils/images/progressindicator_small@2x.png
Binary files differ
diff --git a/src/libs/utils/iwelcomepage.h b/src/libs/utils/iwelcomepage.h
deleted file mode 100644
index e98afadbc43..00000000000
--- a/src/libs/utils/iwelcomepage.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#ifndef IWELCOMEPAGE_H
-#define IWELCOMEPAGE_H
-
-#include "utils_global.h"
-
-#include <QObject>
-
-QT_FORWARD_DECLARE_CLASS(QUrl)
-QT_FORWARD_DECLARE_CLASS(QQmlEngine)
-
-namespace Utils {
-
-class QTCREATOR_UTILS_EXPORT IWelcomePage : public QObject
-{
- Q_OBJECT
-
- Q_PROPERTY(QString title READ title CONSTANT)
- Q_PROPERTY(QUrl pageLocation READ pageLocation CONSTANT)
- Q_PROPERTY(int priority READ priority CONSTANT)
- Q_PROPERTY(bool hasSearchBar READ hasSearchBar CONSTANT)
-
-public:
- enum Id {
- GettingStarted = 0,
- Develop = 1,
- Examples = 2,
- Tutorials = 3,
- UserDefined = 32
- };
-
- IWelcomePage();
- virtual ~IWelcomePage();
-
- virtual QUrl pageLocation() const = 0;
- virtual QString title() const = 0;
- virtual int priority() const { return 0; }
- virtual void facilitateQml(QQmlEngine *) {}
- virtual bool hasSearchBar() const { return false; }
- virtual Id id() const = 0;
-};
-
-}
-
-#endif // IWELCOMEPAGE_H
diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp
index ee3294f9ec3..4047929f101 100644
--- a/src/libs/utils/macroexpander.cpp
+++ b/src/libs/utils/macroexpander.cpp
@@ -372,7 +372,7 @@ void MacroExpander::registerFileVariables(const QByteArray &prefix,
registerVariable(prefix + kFileNamePostfix,
tr("%1: File name without path.").arg(heading),
- [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).fileName(); },
+ [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : Utils::FileName::fromString(tmp).fileName(); },
visibleInChooser);
registerVariable(prefix + kFileBaseNamePostfix,
diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp
index ef27e3b3803..2235802bab3 100644
--- a/src/libs/utils/outputformatter.cpp
+++ b/src/libs/utils/outputformatter.cpp
@@ -73,8 +73,7 @@ void OutputFormatter::appendMessage(const QString &text, const QTextCharFormat &
QTextCursor cursor(m_plainTextEdit->document());
cursor.movePosition(QTextCursor::End);
- foreach (const FormattedText &output,
- m_escapeCodeHandler->parseText(FormattedText(text, format))) {
+ foreach (const FormattedText &output, parseAnsi(text, format)) {
int startPos = 0;
int crPos = -1;
while ((crPos = output.text.indexOf(QLatin1Char('\r'), startPos)) >= 0) {
@@ -92,6 +91,11 @@ QTextCharFormat OutputFormatter::charFormat(OutputFormat format) const
return m_formats[format];
}
+QList<FormattedText> OutputFormatter::parseAnsi(const QString &text, const QTextCharFormat &format)
+{
+ return m_escapeCodeHandler->parseText(FormattedText(text, format));
+}
+
void OutputFormatter::append(QTextCursor &cursor, const QString &text,
const QTextCharFormat &format)
{
@@ -163,6 +167,5 @@ void OutputFormatter::setFont(const QFont &font)
void OutputFormatter::flush()
{
- if (m_escapeCodeHandler)
- m_escapeCodeHandler->endFormatScope();
+ m_escapeCodeHandler->endFormatScope();
}
diff --git a/src/libs/utils/outputformatter.h b/src/libs/utils/outputformatter.h
index 7280d3e09ef..503e73ab73a 100644
--- a/src/libs/utils/outputformatter.h
+++ b/src/libs/utils/outputformatter.h
@@ -47,6 +47,7 @@ QT_END_NAMESPACE
namespace Utils {
class AnsiEscapeCodeHandler;
+class FormattedText;
class QTCREATOR_UTILS_EXPORT OutputFormatter : public QObject
{
@@ -71,6 +72,7 @@ protected:
void initFormats();
virtual void clearLastLine();
QTextCharFormat charFormat(OutputFormat format) const;
+ QList<Utils::FormattedText> parseAnsi(const QString &text, const QTextCharFormat &format);
void append(QTextCursor &cursor, const QString &text, const QTextCharFormat &format);
private:
diff --git a/src/libs/utils/persistentsettings.cpp b/src/libs/utils/persistentsettings.cpp
index b5493ee5d81..1a69acfc3e2 100644
--- a/src/libs/utils/persistentsettings.cpp
+++ b/src/libs/utils/persistentsettings.cpp
@@ -339,11 +339,11 @@ PersistentSettingsReader::PersistentSettingsReader()
{
}
-QVariant PersistentSettingsReader::restoreValue(const QString &variable) const
+QVariant PersistentSettingsReader::restoreValue(const QString &variable, const QVariant &defaultValue) const
{
if (m_valueMap.contains(variable))
return m_valueMap.value(variable);
- return QVariant();
+ return defaultValue;
}
QVariantMap PersistentSettingsReader::restoreValues() const
diff --git a/src/libs/utils/persistentsettings.h b/src/libs/utils/persistentsettings.h
index c092da9eee1..f8187412d75 100644
--- a/src/libs/utils/persistentsettings.h
+++ b/src/libs/utils/persistentsettings.h
@@ -45,7 +45,7 @@ class QTCREATOR_UTILS_EXPORT PersistentSettingsReader
{
public:
PersistentSettingsReader();
- QVariant restoreValue(const QString &variable) const;
+ QVariant restoreValue(const QString &variable, const QVariant &defaultValue = QVariant()) const;
QVariantMap restoreValues() const;
bool load(const FileName &fileName);
diff --git a/src/libs/utils/portlist.cpp b/src/libs/utils/portlist.cpp
index cdad1958815..5bf0e098fc2 100644
--- a/src/libs/utils/portlist.cpp
+++ b/src/libs/utils/portlist.cpp
@@ -63,7 +63,7 @@ public:
try {
if (!atEnd())
parseElemList();
- } catch (ParseException &e) {
+ } catch (const ParseException &e) {
qWarning("Malformed ports specification: %s", e.error);
}
return m_portList;
diff --git a/src/libs/utils/progressindicator.cpp b/src/libs/utils/progressindicator.cpp
new file mode 100644
index 00000000000..85ce2f1d88a
--- /dev/null
+++ b/src/libs/utils/progressindicator.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "progressindicator.h"
+
+#include "qtcassert.h"
+#include "stylehelper.h"
+
+#include <QEvent>
+#include <QPainter>
+#include <QPixmap>
+
+using namespace Utils;
+
+ProgressIndicator::ProgressIndicator(IndicatorSize size, QWidget *parent)
+ : QWidget(parent),
+ m_rotation(0)
+{
+ setAttribute(Qt::WA_TransparentForMouseEvents);
+ m_timer.setSingleShot(false);
+ connect(&m_timer, &QTimer::timeout, this, &ProgressIndicator::step);
+ setIndicatorSize(size);
+}
+
+static QString imageFileNameForIndicatorSize(ProgressIndicator::IndicatorSize size)
+{
+ switch (size) {
+ case ProgressIndicator::Large:
+ return QLatin1String(":/utils/images/progressindicator_big.png");
+ case ProgressIndicator::Medium:
+ return QLatin1String(":/utils/images/progressindicator_medium.png");
+ case ProgressIndicator::Small:
+ default:
+ return QLatin1String(":/utils/images/progressindicator_small.png");
+ }
+}
+
+void ProgressIndicator::setIndicatorSize(ProgressIndicator::IndicatorSize size)
+{
+ m_size = size;
+ m_rotationStep = size == Small ? 45 : 30;
+ m_timer.setInterval(size == Small ? 100 : 80);
+ m_pixmap.load(StyleHelper::dpiSpecificImageFile(
+ imageFileNameForIndicatorSize(size)));
+ updateGeometry();
+}
+
+ProgressIndicator::IndicatorSize ProgressIndicator::indicatorSize() const
+{
+ return m_size;
+}
+
+QSize ProgressIndicator::sizeHint() const
+{
+ return m_pixmap.size() / m_pixmap.devicePixelRatio();
+}
+
+void ProgressIndicator::attachToWidget(QWidget *parent)
+{
+ if (parentWidget())
+ parentWidget()->removeEventFilter(this);
+ setParent(parent);
+ parent->installEventFilter(this);
+ resizeToParent();
+ raise();
+}
+
+void ProgressIndicator::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ p.setRenderHint(QPainter::SmoothPixmapTransform);
+ QPoint translate(rect().width() / 2, rect().height() / 2);
+ QTransform t;
+ t.translate(translate.x(), translate.y());
+ t.rotate(m_rotation);
+ t.translate(-translate.x(), -translate.y());
+ p.setTransform(t);
+ QSize pixmapUserSize(m_pixmap.size() / m_pixmap.devicePixelRatio());
+ p.drawPixmap(QPoint((rect().width() - pixmapUserSize.width()) / 2,
+ (rect().height() - pixmapUserSize.height()) / 2),
+ m_pixmap);
+}
+
+void ProgressIndicator::showEvent(QShowEvent *)
+{
+ m_timer.start();
+}
+
+void ProgressIndicator::hideEvent(QHideEvent *)
+{
+ m_timer.stop();
+}
+
+bool ProgressIndicator::eventFilter(QObject *obj, QEvent *ev)
+{
+ if (obj == parent() && ev->type() == QEvent::Resize) {
+ resizeToParent();
+ }
+ return QWidget::eventFilter(obj, ev);
+}
+
+void ProgressIndicator::step()
+{
+ m_rotation = (m_rotation + m_rotationStep + 360) % 360;
+ update();
+}
+
+void ProgressIndicator::resizeToParent()
+{
+ QTC_ASSERT(parentWidget(), return);
+ setGeometry(QRect(QPoint(0, 0), parentWidget()->size()));
+}
+
diff --git a/src/libs/utils/progressindicator.h b/src/libs/utils/progressindicator.h
new file mode 100644
index 00000000000..30561e2afc8
--- /dev/null
+++ b/src/libs/utils/progressindicator.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+
+#ifndef PROGRESSINDICATOR_H
+#define PROGRESSINDICATOR_H
+
+#include "utils_global.h"
+
+#include <QTimer>
+#include <QWidget>
+
+namespace Utils {
+
+namespace Internal { class ProgressIndicatorPrivate; }
+
+class QTCREATOR_UTILS_EXPORT ProgressIndicator : public QWidget
+{
+ Q_OBJECT
+public:
+ enum IndicatorSize {
+ Small,
+ Medium,
+ Large
+ };
+
+ explicit ProgressIndicator(IndicatorSize size, QWidget *parent = 0);
+
+ void setIndicatorSize(IndicatorSize size);
+ IndicatorSize indicatorSize() const;
+
+ QSize sizeHint() const;
+
+ void attachToWidget(QWidget *parent);
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void showEvent(QShowEvent *);
+ void hideEvent(QHideEvent *);
+ bool eventFilter(QObject *obj, QEvent *ev);
+
+private:
+ void step();
+ void resizeToParent();
+
+ ProgressIndicator::IndicatorSize m_size;
+ int m_rotationStep;
+ int m_rotation;
+ QTimer m_timer;
+ QPixmap m_pixmap;
+};
+
+} // Utils
+
+#endif // PROGRESSINDICATOR_H
diff --git a/src/libs/utils/projectintropage.cpp b/src/libs/utils/projectintropage.cpp
index 6e5dc7777ca..5769afe7636 100644
--- a/src/libs/utils/projectintropage.cpp
+++ b/src/libs/utils/projectintropage.cpp
@@ -179,10 +179,8 @@ bool ProjectIntroPage::validate()
}
// Check existence of the directory
- QString projectDir = path();
- projectDir += QDir::separator();
- projectDir += d->m_ui.nameLineEdit->text();
- const QFileInfo projectDirFile(projectDir);
+ const QFileInfo projectDirFile(path() + QLatin1Char('/')
+ + QDir::fromNativeSeparators(d->m_ui.nameLineEdit->text()));
if (!projectDirFile.exists()) { // All happy
hideStatusLabel();
return nameValid;
diff --git a/src/libs/utils/reloadpromptutils.cpp b/src/libs/utils/reloadpromptutils.cpp
index 73ae4dabdaf..d20aa0e1aae 100644
--- a/src/libs/utils/reloadpromptutils.cpp
+++ b/src/libs/utils/reloadpromptutils.cpp
@@ -28,6 +28,7 @@
**
****************************************************************************/
+#include "fileutils.h"
#include "reloadpromptutils.h"
#include <QCoreApplication>
@@ -37,7 +38,7 @@
namespace Utils {
-QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &fileName,
+QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const FileName &fileName,
bool modified,
QWidget *parent)
{
@@ -53,8 +54,8 @@ QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &fileName,
msg = QCoreApplication::translate("Utils::reloadPrompt",
"The file <i>%1</i> has changed outside Qt Creator. Do you want to reload it?");
}
- msg = msg.arg(QFileInfo(fileName).fileName());
- return reloadPrompt(title, msg, QDir::toNativeSeparators(fileName), parent);
+ msg = msg.arg(fileName.fileName());
+ return reloadPrompt(title, msg, fileName.toUserOutput(), parent);
}
QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title,
diff --git a/src/libs/utils/reloadpromptutils.h b/src/libs/utils/reloadpromptutils.h
index c3a53c9021c..65e564b438a 100644
--- a/src/libs/utils/reloadpromptutils.h
+++ b/src/libs/utils/reloadpromptutils.h
@@ -39,6 +39,7 @@ class QWidget;
QT_END_NAMESPACE
namespace Utils {
+class FileName;
enum ReloadPromptAnswer {
ReloadCurrent,
@@ -48,7 +49,7 @@ enum ReloadPromptAnswer {
CloseCurrent
};
-QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &fileName,
+QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const FileName &fileName,
bool modified,
QWidget *parent);
QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title,
diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp
index 0666740641f..6bcc01a8887 100644
--- a/src/libs/utils/synchronousprocess.cpp
+++ b/src/libs/utils/synchronousprocess.cpp
@@ -385,7 +385,7 @@ static bool isGuiThread()
}
SynchronousProcessResponse SynchronousProcess::run(const QString &binary,
- const QStringList &args)
+ const QStringList &args)
{
if (debug)
qDebug() << '>' << Q_FUNC_INFO << binary << args;
diff --git a/src/libs/utils/theme/theme.cpp b/src/libs/utils/theme/theme.cpp
index 3fd18c77c69..97a433e9554 100644
--- a/src/libs/utils/theme/theme.cpp
+++ b/src/libs/utils/theme/theme.cpp
@@ -116,7 +116,7 @@ QPair<QColor, QString> Theme::readNamedColor(const QString &color) const
bool ok = true;
const QRgb rgba = color.toLongLong(&ok, 16);
if (!ok) {
- qWarning("Color '%s' is neither a named color nor a valid color", qPrintable(color));
+ qWarning("Color \"%s\" is neither a named color nor a valid color", qPrintable(color));
return qMakePair(Qt::black, QString());
}
return qMakePair(QColor::fromRgba(rgba), QString());
diff --git a/src/libs/utils/tooltip/tipcontents.cpp b/src/libs/utils/tooltip/tipcontents.cpp
deleted file mode 100644
index e28c3713199..00000000000
--- a/src/libs/utils/tooltip/tipcontents.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#include "tipcontents.h"
-#include "tooltip.h"
-#include "tips.h"
-
-#include <utils/qtcassert.h>
-
-#include <QtGlobal>
-
-namespace Utils {
-
-TipContent::TipContent()
-{}
-
-TipContent::~TipContent()
-{}
-
-ColorContent::ColorContent(const QColor &color) : m_color(color)
-{}
-
-ColorContent::~ColorContent()
-{}
-
-TipContent *ColorContent::clone() const
-{
- return new ColorContent(*this);
-}
-
-int ColorContent::typeId() const
-{
- return COLOR_CONTENT_ID;
-}
-
-bool ColorContent::isValid() const
-{
- return m_color.isValid();
-}
-
-bool ColorContent::isInteractive() const
-{
- return false;
-}
-
-int ColorContent::showTime() const
-{
- return 4000;
-}
-
-bool ColorContent::equals(const TipContent &tipContent) const
-{
- if (typeId() == tipContent.typeId()) {
- if (m_color == static_cast<const ColorContent &>(tipContent).m_color)
- return true;
- }
- return false;
-}
-
-const QColor &ColorContent::color() const
-{
- return m_color;
-}
-
-TextContent::TextContent(const QString &text) : m_text(text)
-{}
-
-TextContent::~TextContent()
-{}
-
-TipContent *TextContent::clone() const
-{
- return new TextContent(*this);
-}
-
-int TextContent::typeId() const
-{
- return TEXT_CONTENT_ID;
-}
-
-bool TextContent::isValid() const
-{
- return !m_text.isEmpty();
-}
-
-bool TextContent::isInteractive() const
-{
- return false;
-}
-
-int TextContent::showTime() const
-{
- return 10000 + 40 * qMax(0, m_text.length() - 100);
-}
-
-bool TextContent::equals(const TipContent &tipContent) const
-{
- if (typeId() == tipContent.typeId()) {
- if (m_text == static_cast<const TextContent &>(tipContent).m_text)
- return true;
- }
- return false;
-}
-
-const QString &TextContent::text() const
-{
- return m_text;
-}
-
-WidgetContent::WidgetContent(QWidget *w, bool interactive) :
- m_widget(w), m_interactive(interactive)
-{
-}
-
-TipContent *WidgetContent::clone() const
-{
- return new WidgetContent(m_widget, m_interactive);
-}
-
-int WidgetContent::typeId() const
-{
- return WIDGET_CONTENT_ID;
-}
-
-bool WidgetContent::isValid() const
-{
- return m_widget;
-}
-
-bool WidgetContent::isInteractive() const
-{
- return m_interactive;
-}
-
-void WidgetContent::setInteractive(bool i)
-{
- m_interactive = i;
-}
-
-int WidgetContent::showTime() const
-{
- return 30000;
-}
-
-bool WidgetContent::equals(const TipContent &tipContent) const
-{
- if (typeId() == tipContent.typeId()) {
- if (m_widget == static_cast<const WidgetContent &>(tipContent).m_widget)
- return true;
- }
- return false;
-}
-
-bool WidgetContent::pinToolTip(QWidget *w, QWidget *parent)
-{
- QTC_ASSERT(w, return false);
- // Find the parent WidgetTip, tell it to pin/release the
- // widget and close.
- for (QWidget *p = w->parentWidget(); p ; p = p->parentWidget()) {
- if (Internal::WidgetTip *wt = qobject_cast<Internal::WidgetTip *>(p)) {
- wt->pinToolTipWidget(parent);
- ToolTip::hide();
- return true;
- }
- }
- return false;
-}
-
-} // namespace Utils
diff --git a/src/libs/utils/tooltip/tipcontents.h b/src/libs/utils/tooltip/tipcontents.h
deleted file mode 100644
index 7d2c91c1b0c..00000000000
--- a/src/libs/utils/tooltip/tipcontents.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://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 http://www.qt.io/terms-conditions. For further information
-** use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#ifndef TIPCONTENTS_H
-#define TIPCONTENTS_H
-
-#include "../utils_global.h"
-
-#include <QString>
-#include <QColor>
-#include <QWidget>
-
-namespace Utils {
-
-class QTCREATOR_UTILS_EXPORT TipContent
-{
-protected:
- TipContent();
-
-public:
- virtual ~TipContent();
-
- virtual TipContent *clone() const = 0;
- virtual int typeId() const = 0;
- virtual bool isValid() const = 0;
- virtual bool isInteractive() const = 0;
- virtual int showTime() const = 0;
- virtual bool equals(const TipContent &tipContent) const = 0;
-};
-
-class QTCREATOR_UTILS_EXPORT ColorContent : public TipContent
-{
-public:
- ColorContent(const QColor &color);
- virtual ~ColorContent();
-
- virtual TipContent *clone() const;
- virtual int typeId() const;
- virtual bool isValid() const;
- virtual bool isInteractive() const;
- virtual int showTime() const;
- virtual bool equals(const TipContent &tipContent) const;
-
- const QColor &color() const;
-
- static const int COLOR_CONTENT_ID = 0;
-
-private:
- QColor m_color;
-};
-
-class QTCREATOR_UTILS_EXPORT TextContent : public TipContent
-{
-public:
- TextContent(const QString &text);
- virtual ~TextContent();
-
- virtual TipContent *clone() const;
- virtual int typeId() const;
- virtual bool isValid() const;
- virtual bool isInteractive() const;
- virtual int showTime() const;
- virtual bool equals(const TipContent &tipContent) const;
-
- const QString &text() const;
-
- static const int TEXT_CONTENT_ID = 1;
-
-private:
- QString m_text;
-};
-
-// A content for displaying any widget (with a layout).
-class QTCREATOR_UTILS_EXPORT WidgetContent : public TipContent
-{
-public:
- explicit WidgetContent(QWidget *w, bool interactive = false);
-
- virtual TipContent *clone() const;
- virtual int typeId() const;
- virtual bool isValid() const;
- virtual int showTime() const;
- virtual bool isInteractive() const;
- void setInteractive(bool i);
-
- virtual bool equals(const TipContent &tipContent) const;
-
- // Helper to 'pin' (show as real window) a tooltip shown
- // using WidgetContent
- static bool pinToolTip(QWidget *w, QWidget *parent);
-
- static const int WIDGET_CONTENT_ID = 42;
-
- QWidget *widget() const { return m_widget; }
-
-private:
- QWidget *m_widget;
- bool m_interactive;
-};
-
-} // namespace Utils
-
-#endif // TIPCONTENTS_H
diff --git a/src/libs/utils/tooltip/tips.cpp b/src/libs/utils/tooltip/tips.cpp
index 159eeb9abf8..9fd0121a682 100644
--- a/src/libs/utils/tooltip/tips.cpp
+++ b/src/libs/utils/tooltip/tips.cpp
@@ -29,7 +29,7 @@
****************************************************************************/
#include "tips.h"
-#include "tipcontents.h"
+#include "tooltip.h"
#include "reuse.h"
#include <utils/qtcassert.h>
@@ -49,59 +49,32 @@
#include <QVBoxLayout>
namespace Utils {
- namespace Internal {
-
-namespace {
- // @todo: Reuse...
- QPixmap tilePixMap(int size)
- {
- const int checkerbordSize= size;
- QPixmap tilePixmap(checkerbordSize * 2, checkerbordSize * 2);
- tilePixmap.fill(Qt::white);
- QPainter tilePainter(&tilePixmap);
- QColor color(220, 220, 220);
- tilePainter.fillRect(0, 0, checkerbordSize, checkerbordSize, color);
- tilePainter.fillRect(checkerbordSize, checkerbordSize, checkerbordSize, checkerbordSize, color);
- return tilePixmap;
- }
-}
+namespace Internal {
QTipLabel::QTipLabel(QWidget *parent) :
- QLabel(parent, Qt::ToolTip | Qt::BypassGraphicsProxyWidget),
- m_tipContent(0)
+ QLabel(parent, Qt::ToolTip | Qt::BypassGraphicsProxyWidget)
{}
-QTipLabel::~QTipLabel()
-{
- TipContent *tmpTipContent = m_tipContent;
- m_tipContent = 0;
- delete tmpTipContent;
-}
-
-bool QTipLabel::isInteractive() const
-{
- return m_tipContent && m_tipContent->isInteractive();
-}
-void QTipLabel::setContent(const TipContent &content)
+ColorTip::ColorTip(QWidget *parent)
+ : QTipLabel(parent)
{
- TipContent *tmpTipContent = m_tipContent;
- m_tipContent = content.clone();
- delete tmpTipContent;
+ resize(40, 40);
}
-const TipContent &QTipLabel::content() const
-{ return *m_tipContent; }
-
-ColorTip::ColorTip(QWidget *parent) : QTipLabel(parent)
+void ColorTip::setContent(const QVariant &content)
{
- resize(QSize(40, 40));
- m_tilePixMap = tilePixMap(10);
+ m_color = content.value<QColor>();
+
+ const int size = 10;
+ m_tilePixmap = QPixmap(size * 2, size * 2);
+ m_tilePixmap.fill(Qt::white);
+ QPainter tilePainter(&m_tilePixmap);
+ QColor col(220, 220, 220);
+ tilePainter.fillRect(0, 0, size, size, col);
+ tilePainter.fillRect(size, size, size, size, col);
}
-ColorTip::~ColorTip()
-{}
-
void ColorTip::configure(const QPoint &pos, QWidget *w)
{
Q_UNUSED(pos)
@@ -110,31 +83,32 @@ void ColorTip::configure(const QPoint &pos, QWidget *w)
update();
}
-bool ColorTip::canHandleContentReplacement(const TipContent &content) const
+bool ColorTip::canHandleContentReplacement(int typeId) const
{
- if (content.typeId() == ColorContent::COLOR_CONTENT_ID)
- return true;
- return false;
+ return typeId == ToolTip::ColorContent;
+}
+
+bool ColorTip::equals(int typeId, const QVariant &other) const
+{
+ return typeId == ToolTip::ColorContent && other == m_color;
}
void ColorTip::paintEvent(QPaintEvent *event)
{
QTipLabel::paintEvent(event);
- const QColor &color = static_cast<const ColorContent &>(content()).color();
-
QPen pen;
pen.setWidth(1);
- if (color.value() > 100)
- pen.setColor(color.darker());
+ if (m_color.value() > 100)
+ pen.setColor(m_color.darker());
else
- pen.setColor(color.lighter());
+ pen.setColor(m_color.lighter());
QPainter painter(this);
painter.setPen(pen);
- painter.setBrush(color);
+ painter.setBrush(m_color);
QRect r(0, 0, rect().width() - 1, rect().height() - 1);
- painter.drawTiledPixmap(r, m_tilePixMap);
+ painter.drawTiledPixmap(r, m_tilePixmap);
painter.drawRect(r);
}
@@ -150,13 +124,14 @@ TextTip::TextTip(QWidget *parent) : QTipLabel(parent)
setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0);
}
-TextTip::~TextTip()
-{}
+void TextTip::setContent(const QVariant &content)
+{
+ m_text = content.toString();
+}
void TextTip::configure(const QPoint &pos, QWidget *w)
{
- const QString &text = static_cast<const TextContent &>(content()).text();
- setText(text);
+ setText(m_text);
// Make it look good with the default ToolTip font on Mac, which has a small descent.
QFontMetrics fm(font());
@@ -181,11 +156,19 @@ void TextTip::configure(const QPoint &pos, QWidget *w)
resize(tipWidth, heightForWidth(tipWidth) + extraHeight);
}
-bool TextTip::canHandleContentReplacement(const TipContent &content) const
+bool TextTip::canHandleContentReplacement(int typeId) const
{
- if (content.typeId() == TextContent::TEXT_CONTENT_ID)
- return true;
- return false;
+ return typeId == ToolTip::TextContent;
+}
+
+int TextTip::showTime() const
+{
+ return 10000 + 40 * qMax(0, m_text.size() - 100);
+}
+
+bool TextTip::equals(int typeId, const QVariant &other) const
+{
+ return typeId == ToolTip::TextContent && other.toString() == m_text;
}
void TextTip::paintEvent(QPaintEvent *event)
@@ -217,15 +200,17 @@ WidgetTip::WidgetTip(QWidget *parent) :
setLayout(m_layout);
}
-void WidgetTip::configure(const QPoint &pos, QWidget *)
+void WidgetTip::setContent(const QVariant &content)
{
- const WidgetContent &anyContent = static_cast<const WidgetContent &>(content());
- QWidget *widget = anyContent.widget();
+ m_widget = content.value<QWidget *>();
+}
- QTC_ASSERT(widget && m_layout->count() == 0, return);
+void WidgetTip::configure(const QPoint &pos, QWidget *)
+{
+ QTC_ASSERT(m_widget && m_layout->count() == 0, return);
move(pos);
- m_layout->addWidget(widget);
+ m_layout->addWidget(m_widget);
m_layout->setSizeConstraint(QLayout::SetFixedSize);
adjustSize();
}
@@ -253,12 +238,18 @@ void WidgetTip::pinToolTipWidget(QWidget *parent)
widget->setAttribute(Qt::WA_DeleteOnClose);
}
-bool WidgetTip::canHandleContentReplacement(const TipContent & ) const
+bool WidgetTip::canHandleContentReplacement(int typeId) const
{
// Always create a new widget.
+ Q_UNUSED(typeId);
return false;
}
+bool WidgetTip::equals(int typeId, const QVariant &other) const
+{
+ return typeId == ToolTip::WidgetContent && other.value<QWidget *>() == m_widget;
+}
+
// need to include it here to force it to be inside the namespaces
#include "moc_tips.cpp"
diff --git a/src/libs/utils/tooltip/tips.h b/src/libs/utils/tooltip/tips.h
index 0b43a469096..86a9633e5da 100644
--- a/src/libs/utils/tooltip/tips.h
+++ b/src/libs/utils/tooltip/tips.h
@@ -31,13 +31,13 @@
#ifndef TIPS_H
#define TIPS_H
-#include <QSharedPointer>
+#include "../utils_global.h"
+
#include <QLabel>
#include <QPixmap>
-
-QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
-
-namespace Utils { class TipContent; }
+#include <QSharedPointer>
+#include <QVariant>
+#include <QVBoxLayout>
#ifndef Q_MOC_RUN
namespace Utils {
@@ -48,68 +48,68 @@ namespace Internal {
class QTipLabel : public QLabel
{
Q_OBJECT
-protected:
- QTipLabel(QWidget *parent);
-
public:
- virtual ~QTipLabel();
-
- void setContent(const TipContent &content);
- const TipContent &content() const;
+ QTipLabel(QWidget *parent);
+ virtual void setContent(const QVariant &content) = 0;
+ virtual bool isInteractive() const { return false; }
+ virtual int showTime() const = 0;
virtual void configure(const QPoint &pos, QWidget *w) = 0;
- virtual bool canHandleContentReplacement(const TipContent &content) const = 0;
-
- bool isInteractive() const;
-
-private:
- TipContent *m_tipContent;
+ virtual bool canHandleContentReplacement(int typeId) const = 0;
+ virtual bool equals(int typeId, const QVariant &other) const = 0;
};
-class ColorTip : public QTipLabel
+class TextTip : public QTipLabel
{
- Q_OBJECT
public:
- ColorTip(QWidget *parent);
- virtual ~ColorTip();
+ TextTip(QWidget *parent);
+ virtual void setContent(const QVariant &content);
virtual void configure(const QPoint &pos, QWidget *w);
- virtual bool canHandleContentReplacement(const TipContent &content) const;
-
-private:
+ virtual bool canHandleContentReplacement(int typeId) const;
+ virtual int showTime() const;
+ virtual bool equals(int typeId, const QVariant &other) const;
virtual void paintEvent(QPaintEvent *event);
+ virtual void resizeEvent(QResizeEvent *event);
- QPixmap m_tilePixMap;
+private:
+ QString m_text;
};
-class TextTip : public QTipLabel
+class ColorTip : public QTipLabel
{
- Q_OBJECT
public:
- TextTip(QWidget *parent);
- virtual ~TextTip();
+ ColorTip(QWidget *parent);
+ virtual void setContent(const QVariant &content);
virtual void configure(const QPoint &pos, QWidget *w);
- virtual bool canHandleContentReplacement(const TipContent &content) const;
+ virtual bool canHandleContentReplacement(int typeId) const;
+ virtual int showTime() const { return 4000; }
+ virtual bool equals(int typeId, const QVariant &other) const;
+ virtual void paintEvent(QPaintEvent *event);
private:
- virtual void paintEvent(QPaintEvent *event);
- virtual void resizeEvent(QResizeEvent *event);
+ QColor m_color;
+ QPixmap m_tilePixmap;
};
class WidgetTip : public QTipLabel
{
Q_OBJECT
+
public:
explicit WidgetTip(QWidget *parent = 0);
+ void pinToolTipWidget(QWidget *parent);
+ virtual void setContent(const QVariant &content);
virtual void configure(const QPoint &pos, QWidget *w);
- virtual bool canHandleContentReplacement(const TipContent &content) const;
-
-public slots:
- void pinToolTipWidget(QWidget *parent);
+ virtual bool canHandleContentReplacement(int typeId) const;
+ virtual int showTime() const { return 30000; }
+ virtual bool equals(int typeId, const QVariant &other) const;
+ virtual bool isInteractive() const { return true; }
private:
+ QWidget *m_widget;
QVBoxLayout *m_layout;
};
diff --git a/src/libs/utils/tooltip/tooltip.cpp b/src/libs/utils/tooltip/tooltip.cpp
index 5859dd1f2de..08e05ea4a1d 100644
--- a/src/libs/utils/tooltip/tooltip.cpp
+++ b/src/libs/utils/tooltip/tooltip.cpp
@@ -30,11 +30,11 @@
#include "tooltip.h"
#include "tips.h"
-#include "tipcontents.h"
#include "effects.h"
#include "reuse.h"
#include <utils/hostosinfo.h>
+#include <utils/qtcassert.h>
#include <QString>
#include <QColor>
@@ -51,8 +51,8 @@ using namespace Internal;
ToolTip::ToolTip() : m_tip(0), m_widget(0)
{
- connect(&m_showTimer, SIGNAL(timeout()), this, SLOT(hideTipImmediately()));
- connect(&m_hideDelayTimer, SIGNAL(timeout()), this, SLOT(hideTipImmediately()));
+ connect(&m_showTimer, &QTimer::timeout, this, &ToolTip::hideTipImmediately);
+ connect(&m_hideDelayTimer, &QTimer::timeout, this, &ToolTip::hideTipImmediately);
}
ToolTip::~ToolTip()
@@ -66,9 +66,28 @@ ToolTip *ToolTip::instance()
return &tooltip;
}
-void ToolTip::show(const QPoint &pos, const TipContent &content, QWidget *w, const QRect &rect)
+void ToolTip::show(const QPoint &pos, const QString &content, QWidget *w, const QRect &rect)
{
- instance()->showInternal(pos, content, w, rect);
+ if (content.isEmpty())
+ instance()->hideTipWithDelay();
+ else
+ instance()->showInternal(pos, QVariant(content), TextContent, w, rect);
+}
+
+void ToolTip::show(const QPoint &pos, const QColor &color, QWidget *w, const QRect &rect)
+{
+ if (!color.isValid())
+ instance()->hideTipWithDelay();
+ else
+ instance()->showInternal(pos, QVariant(color), ColorContent, w, rect);
+}
+
+void ToolTip::show(const QPoint &pos, QWidget *content, QWidget *w, const QRect &rect)
+{
+ if (!content)
+ instance()->hideTipWithDelay();
+ else
+ instance()->showInternal(pos, QVariant::fromValue(content), WidgetContent, w, rect);
}
void ToolTip::move(const QPoint &pos, QWidget *w)
@@ -77,27 +96,37 @@ void ToolTip::move(const QPoint &pos, QWidget *w)
instance()->placeTip(pos, w);
}
-void ToolTip::show(const QPoint &pos, const TipContent &content, QWidget *w)
+bool ToolTip::pinToolTip(QWidget *w, QWidget *parent)
{
- show(pos, content, w, QRect());
+ QTC_ASSERT(w, return false);
+ // Find the parent WidgetTip, tell it to pin/release the
+ // widget and close.
+ for (QWidget *p = w->parentWidget(); p ; p = p->parentWidget()) {
+ if (WidgetTip *wt = qobject_cast<WidgetTip *>(p)) {
+ wt->pinToolTipWidget(parent);
+ ToolTip::hide();
+ return true;
+ }
+ }
+ return false;
}
-bool ToolTip::acceptShow(const TipContent &content,
+bool ToolTip::acceptShow(const QVariant &content,
+ int typeId,
const QPoint &pos,
QWidget *w,
const QRect &rect)
{
- if (!validateContent(content))
- return false;
-
if (isVisible()) {
- if (m_tip->canHandleContentReplacement(content)) {
+ if (m_tip->canHandleContentReplacement(typeId)) {
// Reuse current tip.
QPoint localPos = pos;
if (w)
localPos = w->mapFromGlobal(pos);
- if (tipChanged(localPos, content, w))
- setUp(pos, content, w, rect);
+ if (tipChanged(localPos, content, typeId, w)) {
+ m_tip->setContent(content);
+ setUp(pos, w, rect);
+ }
return false;
}
hideTipImmediately();
@@ -114,19 +143,8 @@ bool ToolTip::acceptShow(const TipContent &content,
return true;
}
-bool ToolTip::validateContent(const TipContent &content)
+void ToolTip::setUp(const QPoint &pos, QWidget *w, const QRect &rect)
{
- if (!content.isValid()) {
- if (isVisible())
- hideTipWithDelay();
- return false;
- }
- return true;
-}
-
-void ToolTip::setUp(const QPoint &pos, const TipContent &content, QWidget *w, const QRect &rect)
-{
- m_tip->setContent(content);
m_tip->configure(pos, w);
placeTip(pos, w);
@@ -134,12 +152,12 @@ void ToolTip::setUp(const QPoint &pos, const TipContent &content, QWidget *w, co
if (m_hideDelayTimer.isActive())
m_hideDelayTimer.stop();
- m_showTimer.start(content.showTime());
+ m_showTimer.start(m_tip->showTime());
}
-bool ToolTip::tipChanged(const QPoint &pos, const TipContent &content, QWidget *w) const
+bool ToolTip::tipChanged(const QPoint &pos, const QVariant &content, int typeId, QWidget *w) const
{
- if (!m_tip->content().equals(content) || m_widget != w)
+ if (!m_tip->equals(typeId, content) || m_widget != w)
return true;
if (!m_rect.isNull())
return !m_rect.contains(pos);
@@ -199,27 +217,29 @@ void ToolTip::hideTipImmediately()
qApp->removeEventFilter(this);
}
-void ToolTip::showInternal(const QPoint &pos, const TipContent &content, QWidget *w, const QRect &rect)
+void ToolTip::showInternal(const QPoint &pos, const QVariant &content,
+ int typeId, QWidget *w, const QRect &rect)
{
- if (acceptShow(content, pos, w, rect)) {
+ if (acceptShow(content, typeId, pos, w, rect)) {
QWidget *target = 0;
if (HostOsInfo::isWindowsHost())
target = QApplication::desktop()->screen(Internal::screenNumber(pos, w));
else
target = w;
- switch (content.typeId()) {
- case TextContent::TEXT_CONTENT_ID:
- m_tip = new TextTip(target);
- break;
- case ColorContent::COLOR_CONTENT_ID:
+ switch (typeId) {
+ case ColorContent:
m_tip = new ColorTip(target);
break;
- case WidgetContent::WIDGET_CONTENT_ID:
+ case TextContent:
+ m_tip = new TextTip(target);
+ break;
+ case WidgetContent:
m_tip = new WidgetTip(target);
break;
}
- setUp(pos, content, w, rect);
+ m_tip->setContent(content);
+ setUp(pos, w, rect);
qApp->installEventFilter(this);
showTip();
}
diff --git a/src/libs/utils/tooltip/tooltip.h b/src/libs/utils/tooltip/tooltip.h
index dd3e17cb656..b95d3a32060 100644
--- a/src/libs/utils/tooltip/tooltip.h
+++ b/src/libs/utils/tooltip/tooltip.h
@@ -50,14 +50,13 @@
QT_BEGIN_NAMESPACE
class QPoint;
+class QVariant;
class QWidget;
QT_END_NAMESPACE
namespace Utils {
namespace Internal { class QTipLabel; }
-class TipContent;
-
class QTCREATOR_UTILS_EXPORT ToolTip : public QObject
{
Q_OBJECT
@@ -67,27 +66,33 @@ protected:
public:
~ToolTip();
+ enum {
+ ColorContent = 0,
+ TextContent = 1,
+ WidgetContent = 42
+ };
+
bool eventFilter(QObject *o, QEvent *event);
static ToolTip *instance();
- static void show(const QPoint &pos, const TipContent &content, QWidget *w = 0);
- static void show(const QPoint &pos, const TipContent &content, QWidget *w, const QRect &rect);
+ static void show(const QPoint &pos, const QString &content, QWidget *w = 0, const QRect &rect = QRect());
+ static void show(const QPoint &pos, const QColor &color, QWidget *w = 0, const QRect &rect = QRect());
+ static void show(const QPoint &pos, QWidget *content, QWidget *w = 0, const QRect &rect = QRect());
static void move(const QPoint &pos, QWidget *w);
static void hide();
static bool isVisible();
-protected slots:
- void hideTipImmediately();
-
-protected:
- void showInternal(const QPoint &pos, const TipContent &content, QWidget *w, const QRect &rect);
+ // Helper to 'pin' (show as real window) a tooltip shown
+ // using WidgetContent
+ static bool pinToolTip(QWidget *w, QWidget *parent);
private:
- bool acceptShow(const TipContent &content, const QPoint &pos, QWidget *w, const QRect &rect);
- bool validateContent(const TipContent &content);
- void setUp(const QPoint &pos, const TipContent &content, QWidget *w, const QRect &rect);
- bool tipChanged(const QPoint &pos, const TipContent &content, QWidget *w) const;
+ void showInternal(const QPoint &pos, const QVariant &content, int typeId, QWidget *w, const QRect &rect);
+ void hideTipImmediately();
+ bool acceptShow(const QVariant &content, int typeId, const QPoint &pos, QWidget *w, const QRect &rect);
+ void setUp(const QPoint &pos, QWidget *w, const QRect &rect);
+ bool tipChanged(const QPoint &pos, const QVariant &content, int typeId, QWidget *w) const;
void setTipRect(QWidget *w, const QRect &rect);
void placeTip(const QPoint &pos, QWidget *w);
void showTip();
diff --git a/src/libs/utils/treemodel.cpp b/src/libs/utils/treemodel.cpp
index 2b93d233e41..c582000bcb0 100644
--- a/src/libs/utils/treemodel.cpp
+++ b/src/libs/utils/treemodel.cpp
@@ -31,12 +31,579 @@
#include "treemodel.h"
#include "qtcassert.h"
+#include <QStack>
+#include <QSize>
+
+#define USE_MODEL_TEST 0
+#define USE_INDEX_CHECKS 0
+
+#if USE_INDEX_CHECKS
+#define CHECK_INDEX(index) \
+ do { \
+ if (index.isValid()) { \
+ QTC_CHECK(index.model() == this); \
+ } else { \
+ QTC_CHECK(index.model() == 0); \
+ } \
+ } while (false)
+#else
+#define CHECK_INDEX(index)
+#endif
+
+#if USE_MODEL_TEST
+
+namespace {
+
+class ModelTest : public QObject
+{
+public:
+ ModelTest(QAbstractItemModel *model, QObject *parent = 0);
+
+private:
+ void nonDestructiveBasicTest();
+ void rowCount();
+ void columnCount();
+ void hasIndex();
+ void index();
+ void parent();
+ void data();
+
+protected:
+ void runAllTests();
+ void layoutAboutToBeChanged();
+ void layoutChanged();
+ void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
+ void rowsInserted(const QModelIndex & parent, int start, int end);
+ void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void rowsRemoved(const QModelIndex & parent, int start, int end);
+
+private:
+ void checkChildren(const QModelIndex &parent, int currentDepth = 0);
+
+ QAbstractItemModel *model;
+
+ struct Changing
+ {
+ QModelIndex parent;
+ int oldSize;
+ QVariant last;
+ QVariant next;
+ };
+ QStack<Changing> insert;
+ QStack<Changing> remove;
+
+ bool fetchingMore;
+
+ QList<QPersistentModelIndex> changing;
+};
+
/*!
- \class Utils::TreeModel
+ Connect to all of the models signals. Whenever anything happens
+ recheck everything.
+*/
+ModelTest::ModelTest(QAbstractItemModel *_model, QObject *parent) : QObject(parent), model(_model), fetchingMore(false)
+{
+ Q_ASSERT(model);
- \brief The TreeModel class is a convienience base class for models
- to use in a QTreeView.
+ connect(model, &QAbstractItemModel::columnsAboutToBeInserted,
+ this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::columnsAboutToBeRemoved,
+ this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::columnsInserted,
+ this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::columnsRemoved,
+ this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::dataChanged,
+ this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::headerDataChanged,
+ this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::layoutAboutToBeChanged, this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::layoutChanged, this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::modelReset, this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::rowsAboutToBeInserted,
+ this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::rowsInserted,
+ this, &ModelTest::runAllTests);
+ connect(model, &QAbstractItemModel::rowsRemoved,
+ this, &ModelTest::runAllTests);
+
+ // Special checks for inserting/removing
+ connect(model, &QAbstractItemModel::layoutAboutToBeChanged,
+ this, &ModelTest::layoutAboutToBeChanged);
+ connect(model, &QAbstractItemModel::layoutChanged,
+ this, &ModelTest::layoutChanged);
+
+ connect(model, &QAbstractItemModel::rowsAboutToBeInserted,
+ this, &ModelTest::rowsAboutToBeInserted);
+ connect(model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &ModelTest::rowsAboutToBeRemoved);
+ connect(model, &QAbstractItemModel::rowsInserted,
+ this, &ModelTest::rowsInserted);
+ connect(model, &QAbstractItemModel::rowsRemoved,
+ this, &ModelTest::rowsRemoved);
+
+ runAllTests();
+}
+
+void ModelTest::runAllTests()
+{
+ if (fetchingMore)
+ return;
+ nonDestructiveBasicTest();
+ rowCount();
+ columnCount();
+ hasIndex();
+ index();
+ parent();
+ data();
+}
+
+/*!
+ nonDestructiveBasicTest tries to call a number of the basic functions (not all)
+ to make sure the model doesn't outright segfault, testing the functions that makes sense.
*/
+void ModelTest::nonDestructiveBasicTest()
+{
+ Q_ASSERT(model->buddy(QModelIndex()) == QModelIndex());
+ model->canFetchMore(QModelIndex());
+ Q_ASSERT(model->columnCount(QModelIndex()) >= 0);
+ Q_ASSERT(model->data(QModelIndex()) == QVariant());
+ fetchingMore = true;
+ model->fetchMore(QModelIndex());
+ fetchingMore = false;
+ Qt::ItemFlags flags = model->flags(QModelIndex());
+ Q_ASSERT(flags == Qt::ItemIsDropEnabled || flags == 0);
+ model->hasChildren(QModelIndex());
+ model->hasIndex(0, 0);
+ model->headerData(0, Qt::Horizontal);
+ model->index(0, 0);
+ model->itemData(QModelIndex());
+ QVariant cache;
+ model->match(QModelIndex(), -1, cache);
+ model->mimeTypes();
+ QModelIndex m1 = model->parent(QModelIndex());
+ QModelIndex m2 = QModelIndex();
+ Q_ASSERT(m1 == m2);
+ Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
+ Q_ASSERT(model->rowCount() >= 0);
+ QVariant variant;
+ model->setData(QModelIndex(), variant, -1);
+ model->setHeaderData(-1, Qt::Horizontal, QVariant());
+ model->setHeaderData(999999, Qt::Horizontal, QVariant());
+ QMap<int, QVariant> roles;
+ model->sibling(0, 0, QModelIndex());
+ model->span(QModelIndex());
+ model->supportedDropActions();
+}
+
+/*!
+ Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren()
+
+ Models that are dynamically populated are not as fully tested here.
+ */
+void ModelTest::rowCount()
+{
+ // check top row
+ QModelIndex topIndex = model->index(0, 0, QModelIndex());
+ int rows = model->rowCount(topIndex);
+ Q_ASSERT(rows >= 0);
+ if (rows > 0)
+ Q_ASSERT(model->hasChildren(topIndex) == true);
+
+ QModelIndex secondLevelIndex = model->index(0, 0, topIndex);
+ if (secondLevelIndex.isValid()) { // not the top level
+ // check a row count where parent is valid
+ rows = model->rowCount(secondLevelIndex);
+ Q_ASSERT(rows >= 0);
+ if (rows > 0)
+ Q_ASSERT(model->hasChildren(secondLevelIndex) == true);
+ }
+
+ // The models rowCount() is tested more extensively in checkChildren(),
+ // but this catches the big mistakes
+}
+
+/*!
+ Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren()
+ */
+void ModelTest::columnCount()
+{
+ // check top row
+ QModelIndex topIndex = model->index(0, 0, QModelIndex());
+ Q_ASSERT(model->columnCount(topIndex) >= 0);
+
+ // check a column count where parent is valid
+ QModelIndex childIndex = model->index(0, 0, topIndex);
+ if (childIndex.isValid())
+ Q_ASSERT(model->columnCount(childIndex) >= 0);
+
+ // columnCount() is tested more extensively in checkChildren(),
+ // but this catches the big mistakes
+}
+
+/*!
+ Tests model's implementation of QAbstractItemModel::hasIndex()
+ */
+void ModelTest::hasIndex()
+{
+ // Make sure that invalid values returns an invalid index
+ Q_ASSERT(model->hasIndex(-2, -2) == false);
+ Q_ASSERT(model->hasIndex(-2, 0) == false);
+ Q_ASSERT(model->hasIndex(0, -2) == false);
+
+ int rows = model->rowCount();
+ int columns = model->columnCount();
+
+ // check out of bounds
+ Q_ASSERT(model->hasIndex(rows, columns) == false);
+ Q_ASSERT(model->hasIndex(rows + 1, columns + 1) == false);
+
+ if (rows > 0)
+ Q_ASSERT(model->hasIndex(0, 0) == true);
+
+ // hasIndex() is tested more extensively in checkChildren(),
+ // but this catches the big mistakes
+}
+
+/*!
+ Tests model's implementation of QAbstractItemModel::index()
+ */
+void ModelTest::index()
+{
+ // Make sure that invalid values returns an invalid index
+ Q_ASSERT(model->index(-2, -2) == QModelIndex());
+ Q_ASSERT(model->index(-2, 0) == QModelIndex());
+ Q_ASSERT(model->index(0, -2) == QModelIndex());
+
+ int rows = model->rowCount();
+ int columns = model->columnCount();
+
+ if (rows == 0)
+ return;
+
+ // Catch off by one errors
+ QModelIndex tmp;
+ tmp = model->index(rows, columns);
+ Q_ASSERT(tmp == QModelIndex());
+ tmp = model->index(0, 0);
+ Q_ASSERT(tmp.isValid() == true);
+
+ // Make sure that the same index is *always* returned
+ QModelIndex a = model->index(0, 0);
+ QModelIndex b = model->index(0, 0);
+ Q_ASSERT(a == b);
+
+ // index() is tested more extensively in checkChildren(),
+ // but this catches the big mistakes
+}
+
+/*!
+ Tests model's implementation of QAbstractItemModel::parent()
+ */
+void ModelTest::parent()
+{
+ // Make sure the model wont crash and will return an invalid QModelIndex
+ // when asked for the parent of an invalid index.
+ Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
+
+ if (model->rowCount() == 0)
+ return;
+
+ QModelIndex tmp;
+
+ // Column 0 | Column 1 |
+ // QModelIndex() | |
+ // \- topIndex | topIndex1 |
+ // \- childIndex | childIndex1 |
+
+ // Common error test #1, make sure that a top level index has a parent
+ // that is a invalid QModelIndex.
+ QModelIndex topIndex = model->index(0, 0, QModelIndex());
+ tmp = model->parent(topIndex);
+ Q_ASSERT(tmp == QModelIndex());
+
+ // Common error test #2, make sure that a second level index has a parent
+ // that is the first level index.
+ if (model->rowCount(topIndex) > 0) {
+ QModelIndex childIndex = model->index(0, 0, topIndex);
+ tmp = model->parent(childIndex);
+ Q_ASSERT(tmp == topIndex);
+ }
+
+ // Common error test #3, the second column should NOT have the same children
+ // as the first column in a row.
+ // Usually the second column shouldn't have children.
+ QModelIndex topIndex1 = model->index(0, 1, QModelIndex());
+ if (model->rowCount(topIndex1) > 0) {
+ QModelIndex childIndex = model->index(0, 0, topIndex);
+ QModelIndex childIndex1 = model->index(0, 0, topIndex1);
+ Q_ASSERT(childIndex != childIndex1);
+ }
+
+ // Full test, walk n levels deep through the model making sure that all
+ // parent's children correctly specify their parent.
+ checkChildren(QModelIndex());
+}
+
+/*!
+ Called from the parent() test.
+
+ A model that returns an index of parent X should also return X when asking
+ for the parent of the index.
+
+ This recursive function does pretty extensive testing on the whole model in an
+ effort to catch edge cases.
+
+ This function assumes that rowCount(), columnCount() and index() already work.
+ If they have a bug it will point it out, but the above tests should have already
+ found the basic bugs because it is easier to figure out the problem in
+ those tests then this one.
+ */
+void ModelTest::checkChildren(const QModelIndex &parent, int currentDepth)
+{
+ QModelIndex tmp;
+
+ // First just try walking back up the tree.
+ QModelIndex p = parent;
+ while (p.isValid())
+ p = p.parent();
+
+ // For models that are dynamically populated
+ if (model->canFetchMore(parent)) {
+ fetchingMore = true;
+ model->fetchMore(parent);
+ fetchingMore = false;
+ }
+
+ int rows = model->rowCount(parent);
+ int columns = model->columnCount(parent);
+
+ if (rows > 0)
+ Q_ASSERT(model->hasChildren(parent));
+
+ // Some further testing against rows(), columns(), and hasChildren()
+ Q_ASSERT(rows >= 0);
+ Q_ASSERT(columns >= 0);
+ if (rows > 0)
+ Q_ASSERT(model->hasChildren(parent) == true);
+
+ //qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows
+ // << "columns:" << columns << "parent column:" << parent.column();
+
+ Q_ASSERT(model->hasIndex(rows + 1, 0, parent) == false);
+ for (int r = 0; r < rows; ++r) {
+ if (model->canFetchMore(parent)) {
+ fetchingMore = true;
+ model->fetchMore(parent);
+ fetchingMore = false;
+ }
+ Q_ASSERT(model->hasIndex(r, columns + 1, parent) == false);
+ for (int c = 0; c < columns; ++c) {
+ Q_ASSERT(model->hasIndex(r, c, parent) == true);
+ QModelIndex index = model->index(r, c, parent);
+ // rowCount() and columnCount() said that it existed...
+ Q_ASSERT(index.isValid() == true);
+
+ // index() should always return the same index when called twice in a row
+ QModelIndex modifiedIndex = model->index(r, c, parent);
+ Q_ASSERT(index == modifiedIndex);
+
+ // Make sure we get the same index if we request it twice in a row
+ QModelIndex a = model->index(r, c, parent);
+ QModelIndex b = model->index(r, c, parent);
+ Q_ASSERT(a == b);
+
+ // Some basic checking on the index that is returned
+ Q_ASSERT(index.model() == model);
+ Q_ASSERT(index.row() == r);
+ Q_ASSERT(index.column() == c);
+ // While you can technically return a QVariant usually this is a sign
+ // of an bug in data() Disable if this really is ok in your model.
+ //Q_ASSERT(model->data(index, Qt::DisplayRole).isValid() == true);
+
+ // If the next test fails here is some somewhat useful debug you play with.
+ /*
+ if (model->parent(index) != parent) {
+ qDebug() << r << c << currentDepth << model->data(index).toString()
+ << model->data(parent).toString();
+ qDebug() << index << parent << model->parent(index);
+ // And a view that you can even use to show the model.
+ //QTreeView view;
+ //view.setModel(model);
+ //view.show();
+ }*/
+
+ // Check that we can get back our real parent.
+ //qDebug() << "TTT 1: " << model->parent(index);
+ //qDebug() << "TTT 2: " << parent;
+ //qDebug() << "TTT 3: " << index;
+ tmp = model->parent(index);
+ Q_ASSERT(tmp == parent);
+
+ // recursively go down the children
+ if (model->hasChildren(index) && currentDepth < 10 ) {
+ //qDebug() << r << c << "has children" << model->rowCount(index);
+ checkChildren(index, ++currentDepth);
+ }/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/
+
+ // make sure that after testing the children that the index doesn't change.
+ QModelIndex newerIndex = model->index(r, c, parent);
+ Q_ASSERT(index == newerIndex);
+ }
+ }
+}
+
+/*!
+ Tests model's implementation of QAbstractItemModel::data()
+ */
+void ModelTest::data()
+{
+ // Invalid index should return an invalid qvariant
+ Q_ASSERT(!model->data(QModelIndex()).isValid());
+
+ if (model->rowCount() == 0)
+ return;
+
+ // A valid index should have a valid QVariant data
+ Q_ASSERT(model->index(0, 0).isValid());
+
+ // shouldn't be able to set data on an invalid index
+ Q_ASSERT(model->setData(QModelIndex(), QLatin1String("foo"), Qt::DisplayRole) == false);
+
+ // General Purpose roles that should return a QString
+ QVariant variant = model->data(model->index(0, 0), Qt::ToolTipRole);
+ if (variant.isValid())
+ Q_ASSERT(variant.canConvert(QVariant::String));
+ variant = model->data(model->index(0, 0), Qt::StatusTipRole);
+ if (variant.isValid())
+ Q_ASSERT(variant.canConvert(QVariant::String));
+ variant = model->data(model->index(0, 0), Qt::WhatsThisRole);
+ if (variant.isValid())
+ Q_ASSERT(variant.canConvert(QVariant::String));
+
+ // General Purpose roles that should return a QSize
+ variant = model->data(model->index(0, 0), Qt::SizeHintRole);
+ if (variant.isValid())
+ Q_ASSERT(variant.canConvert(QVariant::Size));
+
+ // General Purpose roles that should return a QFont
+ QVariant fontVariant = model->data(model->index(0, 0), Qt::FontRole);
+ if (fontVariant.isValid())
+ Q_ASSERT(fontVariant.canConvert(QVariant::Font));
+
+ // Check that the alignment is one we know about
+ QVariant textAlignmentVariant = model->data(model->index(0, 0), Qt::TextAlignmentRole);
+ if (textAlignmentVariant.isValid()) {
+ int alignment = textAlignmentVariant.toInt();
+ Q_ASSERT(alignment == (alignment & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)));
+ }
+
+ // General Purpose roles that should return a QColor
+ QVariant colorVariant = model->data(model->index(0, 0), Qt::BackgroundColorRole);
+ if (colorVariant.isValid())
+ Q_ASSERT(colorVariant.canConvert(QVariant::Color));
+
+ colorVariant = model->data(model->index(0, 0), Qt::TextColorRole);
+ if (colorVariant.isValid())
+ Q_ASSERT(colorVariant.canConvert(QVariant::Color));
+
+ // Check that the "check state" is one we know about.
+ QVariant checkStateVariant = model->data(model->index(0, 0), Qt::CheckStateRole);
+ if (checkStateVariant.isValid()) {
+ int state = checkStateVariant.toInt();
+ Q_ASSERT(state == Qt::Unchecked ||
+ state == Qt::PartiallyChecked ||
+ state == Qt::Checked);
+ }
+}
+
+/*!
+ Store what is about to be inserted to make sure it actually happens
+
+ \sa rowsInserted()
+ */
+void ModelTest::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(end);
+ Changing c;
+ c.parent = parent;
+ c.oldSize = model->rowCount(parent);
+ c.last = model->data(model->index(start - 1, 0, parent));
+ c.next = model->data(model->index(start, 0, parent));
+ insert.push(c);
+}
+
+/*!
+ Confirm that what was said was going to happen actually did
+
+ \sa rowsAboutToBeInserted()
+ */
+void ModelTest::rowsInserted(const QModelIndex & parent, int start, int end)
+{
+ Changing c = insert.pop();
+ Q_ASSERT(c.parent == parent);
+ Q_ASSERT(c.oldSize + (end - start + 1) == model->rowCount(parent));
+ Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
+ /*
+ if (c.next != model->data(model->index(end + 1, 0, c.parent))) {
+ qDebug() << start << end;
+ for (int i=0; i < model->rowCount(); ++i)
+ qDebug() << model->index(i, 0).data().toString();
+ qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent));
+ }
+ */
+ Q_ASSERT(c.next == model->data(model->index(end + 1, 0, c.parent)));
+}
+
+void ModelTest::layoutAboutToBeChanged()
+{
+ for (int i = 0; i < qBound(0, model->rowCount(), 100); ++i)
+ changing.append(QPersistentModelIndex(model->index(i, 0)));
+}
+
+void ModelTest::layoutChanged()
+{
+ for (int i = 0; i < changing.count(); ++i) {
+ QPersistentModelIndex p = changing[i];
+ Q_ASSERT(p == model->index(p.row(), p.column(), p.parent()));
+ }
+ changing.clear();
+}
+
+/*!
+ Store what is about to be inserted to make sure it actually happens
+
+ \sa rowsRemoved()
+ */
+void ModelTest::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+{
+ Changing c;
+ c.parent = parent;
+ c.oldSize = model->rowCount(parent);
+ c.last = model->data(model->index(start - 1, 0, parent));
+ c.next = model->data(model->index(end + 1, 0, parent));
+ remove.push(c);
+}
+
+/*!
+ Confirm that what was said was going to happen actually did
+
+ \sa rowsAboutToBeRemoved()
+ */
+void ModelTest::rowsRemoved(const QModelIndex & parent, int start, int end)
+{
+ Changing c = remove.pop();
+ Q_ASSERT(c.parent == parent);
+ Q_ASSERT(c.oldSize - (end - start + 1) == model->rowCount(parent));
+ Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
+ Q_ASSERT(c.next == model->data(model->index(start, 0, c.parent)));
+}
+
+} // anon namespace
+
+#endif // ModelTest
namespace Utils {
@@ -44,22 +611,28 @@ namespace Utils {
// TreeItem
//
TreeItem::TreeItem()
- : m_parent(0), m_lazy(false), m_populated(false),
+ : m_parent(0), m_model(0), m_displays(0), m_lazy(false), m_populated(false),
m_flags(Qt::ItemIsEnabled|Qt::ItemIsSelectable)
{
}
+TreeItem::TreeItem(const QStringList &displays, int flags)
+ : m_parent(0), m_model(0), m_displays(new QStringList(displays)), m_lazy(false), m_populated(false),
+ m_flags(flags)
+{
+}
+
TreeItem::~TreeItem()
{
clear();
+ delete m_displays;
}
TreeItem *TreeItem::child(int pos) const
{
ensurePopulated();
QTC_ASSERT(pos >= 0, return 0);
- QTC_ASSERT(pos < m_children.size(), return 0);
- return m_children.at(pos);
+ return pos < m_children.size() ? m_children.at(pos) : 0;
}
bool TreeItem::isLazy() const
@@ -67,11 +640,6 @@ bool TreeItem::isLazy() const
return m_lazy;
}
-int TreeItem::columnCount() const
-{
- return 1;
-}
-
int TreeItem::rowCount() const
{
ensurePopulated();
@@ -84,9 +652,17 @@ void TreeItem::populate()
QVariant TreeItem::data(int column, int role) const
{
+ if (role == Qt::DisplayRole && m_displays && column >= 0 && column < m_displays->size())
+ return m_displays->at(column);
+ return QVariant();
+}
+
+bool TreeItem::setData(int column, const QVariant &data, int role)
+{
Q_UNUSED(column);
+ Q_UNUSED(data);
Q_UNUSED(role);
- return QVariant();
+ return false;
}
Qt::ItemFlags TreeItem::flags(int column) const
@@ -95,18 +671,82 @@ Qt::ItemFlags TreeItem::flags(int column) const
return m_flags;
}
+bool TreeItem::hasChildren() const
+{
+ return canFetchMore() || rowCount() > 0;
+}
+
+bool TreeItem::canFetchMore() const
+{
+ return false;
+}
+
void TreeItem::prependChild(TreeItem *item)
{
- QTC_CHECK(!item->parent());
- item->m_parent = this;
- m_children.prepend(item);
+ insertChild(0, item);
}
void TreeItem::appendChild(TreeItem *item)
{
+ insertChild(m_children.size(), item);
+}
+
+void TreeItem::insertChild(int pos, TreeItem *item)
+{
QTC_CHECK(!item->parent());
- item->m_parent = this;
- m_children.append(item);
+ QTC_ASSERT(0 <= pos && pos <= m_children.size(), return); // '<= size' is intentional.
+
+ if (m_model && !m_lazy) {
+ QModelIndex idx = index();
+ m_model->beginInsertRows(idx, pos, pos);
+ item->m_parent = this;
+ item->propagateModel(m_model);
+ m_children.insert(m_children.begin() + pos, item);
+ m_model->endInsertRows();
+ } else {
+ item->m_parent = this;
+ m_children.insert(m_children.begin() + pos, item);
+ }
+}
+
+void TreeItem::removeChildren()
+{
+ if (rowCount() == 0)
+ return;
+ if (m_model) {
+ QModelIndex idx = index();
+ m_model->beginRemoveRows(idx, 0, rowCount() - 1);
+ clear();
+ m_model->endRemoveRows();
+ } else {
+ clear();
+ }
+}
+
+void TreeItem::update()
+{
+ if (m_model) {
+ QModelIndex idx = index();
+ m_model->dataChanged(idx.sibling(idx.row(), 0), idx.sibling(idx.row(), m_model->m_columnCount - 1));
+ }
+}
+
+TreeItem *TreeItem::firstChild() const
+{
+ return m_children.isEmpty() ? 0 : m_children.first();
+}
+
+TreeItem *TreeItem::lastChild() const
+{
+ return m_children.isEmpty() ? 0 : m_children.last();
+}
+
+int TreeItem::level() const
+{
+ int l = 0;
+ for (TreeItem *item = this->parent(); item; item = item->parent())
+ ++l;
+ return l;
}
void TreeItem::setLazy(bool on)
@@ -119,6 +759,40 @@ void TreeItem::setFlags(Qt::ItemFlags flags)
m_flags = flags;
}
+QModelIndex TreeItem::index() const
+{
+ QTC_ASSERT(m_model, return QModelIndex());
+ return m_model->indexFromItem(this);
+}
+
+void TreeItem::setModel(TreeModel *model)
+{
+ if (m_model == model)
+ return;
+ m_model = model;
+ foreach (TreeItem *item, m_children)
+ item->setModel(model);
+}
+
+void TreeItem::walkTree(TreeItemVisitor *visitor)
+{
+ if (visitor->preVisit(this)) {
+ ++visitor->m_level;
+ visitor->visit(this);
+ foreach (TreeItem *item, m_children)
+ item->walkTree(visitor);
+ --visitor->m_level;
+ }
+ visitor->postVisit(this);
+}
+
+void TreeItem::walkTree(std::function<void (TreeItem *)> f)
+{
+ f(this);
+ foreach (TreeItem *item, m_children)
+ item->walkTree(f);
+}
+
void TreeItem::clear()
{
while (m_children.size()) {
@@ -128,6 +802,12 @@ void TreeItem::clear()
}
}
+void TreeItem::expand()
+{
+ QTC_ASSERT(m_model, return);
+ m_model->requestExpansion(index());
+}
+
void TreeItem::ensurePopulated() const
{
if (!m_populated) {
@@ -137,12 +817,41 @@ void TreeItem::ensurePopulated() const
}
}
-//
-// TreeModel
-//
+void TreeItem::propagateModel(TreeModel *m)
+{
+ QTC_ASSERT(m, return);
+ QTC_ASSERT(m_model == 0 || m_model == m, return);
+ if (m && !m_model) {
+ m_model = m;
+ foreach (TreeItem *item, m_children)
+ item->propagateModel(m);
+ }
+}
+
+/*!
+ \class Utils::TreeModel
+
+ \brief The TreeModel class is a convienience base class for models
+ to use in a QTreeView.
+*/
+
TreeModel::TreeModel(QObject *parent)
- : QAbstractItemModel(parent), m_root(new TreeItem)
+ : QAbstractItemModel(parent),
+ m_root(new TreeItem)
{
+ m_columnCount = 1;
+ m_root->m_model = this;
+#if USE_MODEL_TEST
+ new ModelTest(this, this);
+#endif
+}
+
+TreeModel::TreeModel(TreeItem *root, QObject *parent)
+ : QAbstractItemModel(parent),
+ m_root(root)
+{
+ m_columnCount = 1;
+ m_root->propagateModel(this);
}
TreeModel::~TreeModel()
@@ -152,11 +861,12 @@ TreeModel::~TreeModel()
QModelIndex TreeModel::parent(const QModelIndex &idx) const
{
- checkIndex(idx);
+ CHECK_INDEX(idx);
if (!idx.isValid())
return QModelIndex();
const TreeItem *item = itemFromIndex(idx);
+ QTC_ASSERT(item, return QModelIndex());
const TreeItem *parent = item->parent();
if (!parent || parent == m_root)
return QModelIndex();
@@ -174,22 +884,31 @@ QModelIndex TreeModel::parent(const QModelIndex &idx) const
int TreeModel::rowCount(const QModelIndex &idx) const
{
- checkIndex(idx);
+ CHECK_INDEX(idx);
if (!idx.isValid())
return m_root->rowCount();
if (idx.column() > 0)
return 0;
- return itemFromIndex(idx)->rowCount();
+ const TreeItem *item = itemFromIndex(idx);
+ QTC_ASSERT(item, return 0);
+ return item->rowCount();
}
int TreeModel::columnCount(const QModelIndex &idx) const
{
- checkIndex(idx);
- if (!idx.isValid())
- return m_root->columnCount();
+ CHECK_INDEX(idx);
if (idx.column() > 0)
return 0;
- return itemFromIndex(idx)->columnCount();
+ return m_columnCount;
+}
+
+bool TreeModel::setData(const QModelIndex &idx, const QVariant &data, int role)
+{
+ TreeItem *item = itemFromIndex(idx);
+ bool res = item ? item->setData(idx.column(), data, role) : false;
+ if (res)
+ emit dataChanged(idx, idx);
+ return res;
}
QVariant TreeModel::data(const QModelIndex &idx, int role) const
@@ -198,21 +917,72 @@ QVariant TreeModel::data(const QModelIndex &idx, int role) const
return item ? item->data(idx.column(), role) : QVariant();
}
+QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section < m_header.size())
+ return m_header.at(section);
+ return QVariant();
+}
+
+bool TreeModel::hasChildren(const QModelIndex &idx) const
+{
+ TreeItem *item = itemFromIndex(idx);
+ return !item || item->hasChildren();
+}
+
Qt::ItemFlags TreeModel::flags(const QModelIndex &idx) const
{
+ if (!idx.isValid())
+ return 0;
TreeItem *item = itemFromIndex(idx);
return item ? item->flags(idx.column())
: (Qt::ItemIsEnabled|Qt::ItemIsSelectable);
}
+bool TreeModel::canFetchMore(const QModelIndex &idx) const
+{
+ if (!idx.isValid())
+ return false;
+ TreeItem *item = itemFromIndex(idx);
+ return item ? item->canFetchMore() : false;
+}
+
+void TreeModel::fetchMore(const QModelIndex &idx)
+{
+ if (!idx.isValid())
+ return;
+ TreeItem *item = itemFromIndex(idx);
+ if (item)
+ item->fetchMore();
+}
+
TreeItem *TreeModel::rootItem() const
{
return m_root;
}
+void TreeModel::setRootItem(TreeItem *item)
+{
+ delete m_root;
+ m_root = item;
+ item->setModel(this);
+}
+
+void TreeModel::setHeader(const QStringList &displays)
+{
+ m_header = displays;
+ m_columnCount = displays.size();
+}
+
+void TreeModel::setColumnCount(int columnCount)
+{
+ m_columnCount = columnCount;
+}
+
QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
{
- checkIndex(parent);
+ CHECK_INDEX(parent);
if (!hasIndex(row, column, parent))
return QModelIndex();
@@ -225,42 +995,96 @@ QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) con
TreeItem *TreeModel::itemFromIndex(const QModelIndex &idx) const
{
- checkIndex(idx);
+ CHECK_INDEX(idx);
TreeItem *item = idx.isValid() ? static_cast<TreeItem*>(idx.internalPointer()) : m_root;
-// CHECK(checkItem(item));
+ QTC_ASSERT(item, return 0);
+ QTC_ASSERT(item->m_model == this, return 0);
return item;
}
QModelIndex TreeModel::indexFromItem(const TreeItem *item) const
{
-// CHECK(checkItem(item));
- return indexFromItemHelper(item, m_root, QModelIndex());
+ QTC_ASSERT(item, return QModelIndex());
+ if (item == m_root)
+ return QModelIndex();
+
+ TreeItem *mitem = const_cast<TreeItem *>(item);
+ int row = item->parent()->m_children.indexOf(mitem);
+ return createIndex(row, 0, mitem);
}
-QModelIndex TreeModel::indexFromItemHelper(const TreeItem *needle,
- TreeItem *parentItem, const QModelIndex &parentIndex) const
+void TreeModel::removeItems()
{
- checkIndex(parentIndex);
- if (needle == parentItem)
- return parentIndex;
- for (int i = parentItem->rowCount(); --i >= 0; ) {
- TreeItem *childItem = parentItem->child(i);
- QModelIndex childIndex = index(i, 0, parentIndex);
- QModelIndex idx = indexFromItemHelper(needle, childItem, childIndex);
- checkIndex(idx);
- if (idx.isValid())
- return idx;
- }
- return QModelIndex();
+ if (m_root)
+ m_root->removeChildren();
}
-void TreeModel::checkIndex(const QModelIndex &index) const
+UntypedTreeLevelItems TreeModel::untypedLevelItems(int level, TreeItem *start) const
{
- if (index.isValid()) {
- QTC_CHECK(index.model() == this);
+ if (start == 0)
+ start = m_root;
+ return UntypedTreeLevelItems(start, level);
+}
+
+UntypedTreeLevelItems TreeModel::untypedLevelItems(TreeItem *start) const
+{
+ return UntypedTreeLevelItems(start, 1);
+}
+
+void TreeModel::removeItem(TreeItem *item)
+{
+#if USE_MODEL_TEST
+ (void) new ModelTest(this, this);
+#endif
+
+ QTC_ASSERT(item, return);
+ TreeItem *parent = item->parent();
+ QTC_ASSERT(parent, return);
+ int pos = parent->m_children.indexOf(item);
+ QTC_ASSERT(pos != -1, return);
+
+ QModelIndex idx = indexFromItem(parent);
+ beginRemoveRows(idx, pos, pos);
+ item->m_parent = 0;
+ parent->m_children.removeAt(pos);
+ endRemoveRows();
+}
+
+//
+// TreeLevelItems
+//
+
+UntypedTreeLevelItems::UntypedTreeLevelItems(TreeItem *item, int level)
+ : m_item(item), m_level(level)
+{}
+
+UntypedTreeLevelItems::const_iterator::const_iterator(TreeItem *base, int level)
+ : m_level(level)
+{
+ QTC_ASSERT(level > 0, return);
+ if (base) {
+ // "begin()"
+ m_depth = 0;
+ // Level x: The item m_item[x] is the m_pos[x]'th child of its
+ // parent, out of m_size[x].
+ m_pos[0] = 0;
+ m_size[0] = 1;
+ m_item[0] = base;
+ goDown();
} else {
- QTC_CHECK(index.model() == 0);
+ // "end()"
+ m_depth = -1;
}
}
+UntypedTreeLevelItems::const_iterator UntypedTreeLevelItems::begin() const
+{
+ return const_iterator(m_item, m_level);
+}
+
+UntypedTreeLevelItems::const_iterator UntypedTreeLevelItems::end() const
+{
+ return const_iterator(0, m_level);
+}
+
} // namespace Utils
diff --git a/src/libs/utils/treemodel.h b/src/libs/utils/treemodel.h
index ffcb0b381df..6e654fdfaab 100644
--- a/src/libs/utils/treemodel.h
+++ b/src/libs/utils/treemodel.h
@@ -33,32 +33,78 @@
#include "utils_global.h"
+#include "algorithm.h"
+#include "qtcassert.h"
+
#include <QAbstractItemModel>
+#include <functional>
+#include <iterator>
+
namespace Utils {
+class TreeItem;
+class TreeModel;
+
+class QTCREATOR_UTILS_EXPORT TreeItemVisitor
+{
+public:
+ TreeItemVisitor() : m_level(0) {}
+ virtual ~TreeItemVisitor() {}
+
+ virtual bool preVisit(TreeItem *) { return true; }
+ virtual void visit(TreeItem *) {}
+ virtual void postVisit(TreeItem *) {}
+
+ int level() const { return m_level; }
+
+private:
+ friend class TreeItem;
+ int m_level;
+};
+
class QTCREATOR_UTILS_EXPORT TreeItem
{
public:
TreeItem();
+ explicit TreeItem(const QStringList &displays, int flags = Qt::ItemIsEnabled);
virtual ~TreeItem();
virtual TreeItem *parent() const { return m_parent; }
virtual TreeItem *child(int pos) const;
virtual bool isLazy() const;
- virtual int columnCount() const;
virtual int rowCount() const;
virtual void populate();
virtual QVariant data(int column, int role) const;
+ virtual bool setData(int column, const QVariant &data, int role);
virtual Qt::ItemFlags flags(int column) const;
+ virtual bool hasChildren() const;
+ virtual bool canFetchMore() const;
+ virtual void fetchMore() {}
+
void prependChild(TreeItem *item);
void appendChild(TreeItem *item);
+ void insertChild(int pos, TreeItem *item);
+ void removeChildren();
+ void update();
+ void expand();
+ TreeItem *firstChild() const;
+ TreeItem *lastChild() const;
+ int level() const;
void setLazy(bool on);
void setPopulated(bool on);
void setFlags(Qt::ItemFlags flags);
+ QVector<TreeItem *> children() const { return m_children; }
+ QModelIndex index() const;
+
+ TreeModel *model() const { return m_model; }
+ void setModel(TreeModel *model);
+
+ void walkTree(TreeItemVisitor *visitor);
+ void walkTree(std::function<void(TreeItem *)> f);
private:
TreeItem(const TreeItem &) Q_DECL_EQ_DELETE;
@@ -66,39 +112,207 @@ private:
void clear();
void ensurePopulated() const;
+ void propagateModel(TreeModel *m);
TreeItem *m_parent; // Not owned.
+ TreeModel *m_model; // Not owned.
QVector<TreeItem *> m_children; // Owned.
+ QStringList *m_displays;
bool m_lazy;
mutable bool m_populated;
Qt::ItemFlags m_flags;
+
+ friend class TreeModel;
+};
+
+class QTCREATOR_UTILS_EXPORT UntypedTreeLevelItems
+{
+public:
+ enum { MaxSearchDepth = 12 }; // FIXME.
+ explicit UntypedTreeLevelItems(TreeItem *item, int level = 1);
+
+ typedef TreeItem *value_type;
+
+ class const_iterator
+ {
+ public:
+ typedef std::forward_iterator_tag iterator_category;
+ typedef TreeItem *value_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef const value_type *pointer;
+ typedef const value_type &reference;
+
+ const_iterator(TreeItem *base, int level);
+
+ TreeItem *operator*() { return m_item[m_depth]; }
+
+ void operator++()
+ {
+ QTC_ASSERT(m_depth == m_level, return);
+
+ int pos = ++m_pos[m_depth];
+ if (pos < m_size[m_depth])
+ m_item[m_depth] = m_item[m_depth - 1]->child(pos);
+ else
+ goUpNextDown();
+ }
+
+ bool operator==(const const_iterator &other) const
+ {
+ if (m_depth != other.m_depth)
+ return false;
+ for (int i = 0; i <= m_depth; ++i)
+ if (m_item[i] != other.m_item[i])
+ return false;
+ return true;
+ }
+
+ bool operator!=(const const_iterator &other) const
+ {
+ return !operator==(other);
+ }
+
+ private:
+ // Result is either an item of the target level, or 'end'.
+ void goDown()
+ {
+ QTC_ASSERT(m_depth != -1, return);
+ QTC_ASSERT(m_depth < m_level, return);
+ do {
+ TreeItem *curr = m_item[m_depth];
+ ++m_depth;
+ int size = curr->rowCount();
+ if (size == 0) {
+ // This is a dead end not reaching to the desired level.
+ goUpNextDown();
+ return;
+ }
+ m_size[m_depth] = size;
+ m_pos[m_depth] = 0;
+ m_item[m_depth] = curr->child(0);
+ } while (m_depth < m_level);
+ // Did not reach the required level? Set to end().
+ if (m_depth != m_level)
+ m_depth = -1;
+ }
+ void goUpNextDown()
+ {
+ // Go up until we can move sidewards.
+ do {
+ --m_depth;
+ if (m_depth < 0)
+ return; // Solid end.
+ } while (++m_pos[m_depth] >= m_size[m_depth]);
+ m_item[m_depth] = m_item[m_depth - 1]->child(m_pos[m_depth]);
+ goDown();
+ }
+
+ int m_level;
+ int m_depth;
+ TreeItem *m_item[MaxSearchDepth];
+ int m_pos[MaxSearchDepth];
+ int m_size[MaxSearchDepth];
+ };
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+private:
+ TreeItem *m_item;
+ int m_level;
+};
+
+template <class T>
+class TreeLevelItems
+{
+public:
+ typedef T value_type;
+
+ explicit TreeLevelItems(const UntypedTreeLevelItems &items) : m_items(items) {}
+
+ struct const_iterator : public UntypedTreeLevelItems::const_iterator
+ {
+ typedef std::forward_iterator_tag iterator_category;
+ typedef T value_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef const value_type *pointer;
+ typedef const value_type &reference;
+
+ const_iterator(UntypedTreeLevelItems::const_iterator it) : UntypedTreeLevelItems::const_iterator(it) {}
+ T operator*() { return static_cast<T>(UntypedTreeLevelItems::const_iterator::operator*()); }
+ };
+
+ const_iterator begin() const { return const_iterator(m_items.begin()); }
+ const_iterator end() const { return const_iterator(m_items.end()); }
+
+private:
+ UntypedTreeLevelItems m_items;
};
class QTCREATOR_UTILS_EXPORT TreeModel : public QAbstractItemModel
{
+ Q_OBJECT
+
public:
explicit TreeModel(QObject *parent = 0);
+ explicit TreeModel(TreeItem *root, QObject *parent = 0);
virtual ~TreeModel();
int rowCount(const QModelIndex &idx = QModelIndex()) const;
int columnCount(const QModelIndex &idx) const;
+ bool setData(const QModelIndex &idx, const QVariant &data, int role);
QVariant data(const QModelIndex &idx, int role) const;
QModelIndex index(int, int, const QModelIndex &idx) const;
QModelIndex parent(const QModelIndex &idx) const;
Qt::ItemFlags flags(const QModelIndex &idx) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ bool hasChildren(const QModelIndex &idx) const;
+
+ bool canFetchMore(const QModelIndex &idx) const;
+ void fetchMore(const QModelIndex &idx);
TreeItem *rootItem() const;
+ void setRootItem(TreeItem *item);
TreeItem *itemFromIndex(const QModelIndex &) const;
QModelIndex indexFromItem(const TreeItem *needle) const;
+ void removeItems();
-private:
- QModelIndex indexFromItemHelper(const TreeItem *needle,
- TreeItem *parentItem, const QModelIndex &parentIndex) const;
+ void setHeader(const QStringList &displays);
+ void setColumnCount(int columnCount);
+
+ UntypedTreeLevelItems untypedLevelItems(int level = 0, TreeItem *start = 0) const;
+ UntypedTreeLevelItems untypedLevelItems(TreeItem *start) const;
- void checkIndex(const QModelIndex &index) const;
+ template <class T>
+ TreeLevelItems<T> treeLevelItems(int level, TreeItem *start = 0) const
+ {
+ return TreeLevelItems<T>(untypedLevelItems(level, start));
+ }
+
+ template <class T>
+ TreeLevelItems<T> treeLevelItems(TreeItem *start) const
+ {
+ return TreeLevelItems<T>(untypedLevelItems(start));
+ }
+
+ template <class T>
+ T findItemAtLevel(int level, std::function<bool(T)> f, TreeItem *start = 0) const
+ {
+ return Utils::findOrDefault(treeLevelItems<T>(level, start), f);
+ }
+
+ void removeItem(TreeItem *item); // item is not destroyed.
+
+signals:
+ void requestExpansion(QModelIndex);
+
+private:
+ friend class TreeItem;
TreeItem *m_root; // Owned.
+ QStringList m_header;
+ int m_columnCount;
};
} // namespace Utils
diff --git a/src/libs/utils/unixutils.cpp b/src/libs/utils/unixutils.cpp
index d6d98973817..a93209d463e 100644
--- a/src/libs/utils/unixutils.cpp
+++ b/src/libs/utils/unixutils.cpp
@@ -28,8 +28,9 @@
**
****************************************************************************/
-
#include "unixutils.h"
+#include "fileutils.h"
+
#include <QSettings>
#include <QFileInfo>
#include <QCoreApplication>
@@ -81,7 +82,7 @@ QString UnixUtils::substituteFileBrowserParameters(const QString &pre, const QSt
} else if (c == QLatin1Char('f')) {
s = QLatin1Char('"') + file + QLatin1Char('"');
} else if (c == QLatin1Char('n')) {
- s = QLatin1Char('"') + QFileInfo(file).fileName() + QLatin1Char('"');
+ s = QLatin1Char('"') + FileName::fromString(file).fileName() + QLatin1Char('"');
} else if (c == QLatin1Char('%')) {
s = c;
} else {
diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri
index f339efdb8a2..34b3549dc8e 100644
--- a/src/libs/utils/utils-lib.pri
+++ b/src/libs/utils/utils-lib.pri
@@ -49,7 +49,6 @@ SOURCES += $$PWD/environment.cpp \
$$PWD/checkablemessagebox.cpp \
$$PWD/styledbar.cpp \
$$PWD/stylehelper.cpp \
- $$PWD/iwelcomepage.cpp \
$$PWD/fancymainwindow.cpp \
$$PWD/detailsbutton.cpp \
$$PWD/detailswidget.cpp \
@@ -82,7 +81,6 @@ SOURCES += $$PWD/environment.cpp \
$$PWD/hostosinfo.cpp \
$$PWD/tooltip/tooltip.cpp \
$$PWD/tooltip/tips.cpp \
- $$PWD/tooltip/tipcontents.cpp \
$$PWD/unixutils.cpp \
$$PWD/ansiescapecodehandler.cpp \
$$PWD/execmenu.cpp \
@@ -93,7 +91,9 @@ SOURCES += $$PWD/environment.cpp \
$$PWD/treeviewcombobox.cpp \
$$PWD/proxycredentialsdialog.cpp \
$$PWD/macroexpander.cpp \
- $$PWD/theme/theme.cpp
+ $$PWD/theme/theme.cpp \
+ $$PWD/progressindicator.cpp \
+ $$PWD/fadingindicator.cpp
win32:SOURCES += $$PWD/consoleprocess_win.cpp
else:SOURCES += $$PWD/consoleprocess_unix.cpp
@@ -139,7 +139,6 @@ HEADERS += \
$$PWD/qtcassert.h \
$$PWD/styledbar.h \
$$PWD/stylehelper.h \
- $$PWD/iwelcomepage.h \
$$PWD/fancymainwindow.h \
$$PWD/detailsbutton.h \
$$PWD/detailswidget.h \
@@ -175,7 +174,6 @@ HEADERS += \
$$PWD/elidinglabel.h \
$$PWD/tooltip/tooltip.h \
$$PWD/tooltip/tips.h \
- $$PWD/tooltip/tipcontents.h \
$$PWD/tooltip/reuse.h \
$$PWD/tooltip/effects.h \
$$PWD/unixutils.h \
@@ -192,7 +190,9 @@ HEADERS += \
$$PWD/proxycredentialsdialog.h \
$$PWD/macroexpander.h \
$$PWD/theme/theme.h \
- $$PWD/theme/theme_p.h
+ $$PWD/theme/theme_p.h \
+ $$PWD/progressindicator.h \
+ $$PWD/fadingindicator.h
FORMS += $$PWD/filewizardpage.ui \
$$PWD/projectintropage.ui \
diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs
index 456dbd7dbc4..603a0e6e49f 100644
--- a/src/libs/utils/utils.qbs
+++ b/src/libs/utils/utils.qbs
@@ -72,6 +72,8 @@ QtcLibrary {
"environmentmodel.h",
"execmenu.cpp",
"execmenu.h",
+ "fadingindicator.cpp",
+ "fadingindicator.h",
"faketooltip.cpp",
"faketooltip.h",
"fancylineedit.cpp",
@@ -101,8 +103,6 @@ QtcLibrary {
"htmldocextractor.h",
"itemviews.cpp",
"itemviews.h",
- "iwelcomepage.cpp",
- "iwelcomepage.h",
"json.cpp",
"json.h",
"linecolumnlabel.cpp",
@@ -132,6 +132,8 @@ QtcLibrary {
"persistentsettings.h",
"portlist.cpp",
"portlist.h",
+ "progressindicator.cpp",
+ "progressindicator.h",
"projectintropage.cpp",
"projectintropage.h",
"projectintropage.ui",
@@ -204,6 +206,10 @@ QtcLibrary {
"images/crumblepath-segment-selected-end.png",
"images/crumblepath-segment-selected.png",
"images/crumblepath-segment.png",
+ "images/progressindicator_big.png",
+ "images/progressindicator_big@2x.png",
+ "images/progressindicator_small.png",
+ "images/progressindicator_small@2x.png",
"images/triangle_vert.png",
]
@@ -223,8 +229,6 @@ QtcLibrary {
files: [
"effects.h",
"reuse.h",
- "tipcontents.cpp",
- "tipcontents.h",
"tips.cpp",
"tips.h",
"tooltip.cpp",
diff --git a/src/libs/utils/utils.qrc b/src/libs/utils/utils.qrc
index 2748bccb6c8..c7be7e8de8e 100644
--- a/src/libs/utils/utils.qrc
+++ b/src/libs/utils/utils.qrc
@@ -7,6 +7,12 @@
<file>images/crumblepath-segment-hover.png</file>
<file>images/crumblepath-segment-selected-end.png</file>
<file>images/crumblepath-segment-selected.png</file>
+ <file>images/progressindicator_big.png</file>
+ <file>images/progressindicator_big@2x.png</file>
+ <file>images/progressindicator_medium.png</file>
+ <file>images/progressindicator_medium@2x.png</file>
+ <file>images/progressindicator_small.png</file>
+ <file>images/progressindicator_small@2x.png</file>
<file>images/triangle_vert.png</file>
</qresource>
</RCC>
diff --git a/src/libs/utils/wizard.cpp b/src/libs/utils/wizard.cpp
index a551825e37d..022ce467826 100644
--- a/src/libs/utils/wizard.cpp
+++ b/src/libs/utils/wizard.cpp
@@ -322,9 +322,9 @@ Wizard::Wizard(QWidget *parent, Qt::WindowFlags flags) :
{
d_ptr->q_ptr = this;
d_ptr->m_wizardProgress = new WizardProgress(this);
- connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(_q_currentPageChanged(int)));
- connect(this, SIGNAL(pageAdded(int)), this, SLOT(_q_pageAdded(int)));
- connect(this, SIGNAL(pageRemoved(int)), this, SLOT(_q_pageRemoved(int)));
+ connect(this, &QWizard::currentIdChanged, this, &Wizard::_q_currentPageChanged);
+ connect(this, &QWizard::pageAdded, this, &Wizard::_q_pageAdded);
+ connect(this, &QWizard::pageRemoved, this, &Wizard::_q_pageRemoved);
setSideWidget(new LinearProgressWidget(d_ptr->m_wizardProgress, this));
setOption(QWizard::NoCancelButton, false);
setOption(QWizard::NoDefaultButton, false);
diff --git a/src/libs/utils/wizardpage.h b/src/libs/utils/wizardpage.h
index 13a9871d302..5ff240339b4 100644
--- a/src/libs/utils/wizardpage.h
+++ b/src/libs/utils/wizardpage.h
@@ -52,6 +52,10 @@ public:
void registerFieldWithName(const QString &name, QWidget *widget,
const char *property = 0, const char *changedSignal = 0);
+signals:
+ // Emitted when there is something that the developer using this page should be aware of.
+ void reportError(const QString &errorMessage);
+
private:
QSet<QString> m_toRegister;
};