forked from qt-creator/qt-creator
MiniProjectTargetSelector: Merge two pairs of classes
Change-Id: I7b6e1c603da2c6457e150fcb5f60c11a844b2f34 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -92,76 +92,43 @@ static QIcon createCenteredIcon(const QIcon &icon, const QIcon &overlay)
|
||||
return QIcon(targetPixmap);
|
||||
}
|
||||
|
||||
class SelectorView : public TreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SelectorView(QWidget *parent);
|
||||
|
||||
void setMaxCount(int maxCount);
|
||||
int maxCount();
|
||||
|
||||
int optimalWidth() const;
|
||||
void setOptimalWidth(int width);
|
||||
|
||||
int padding();
|
||||
|
||||
private:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void keyReleaseEvent(QKeyEvent *event) override;
|
||||
|
||||
int m_maxCount = 0;
|
||||
int m_optimalWidth = 0;
|
||||
};
|
||||
|
||||
// The project-specific classes look annoyingly similar to the generic ones.
|
||||
// Can we merge them?
|
||||
class SelectorProjectItem : public TreeItem
|
||||
{
|
||||
public:
|
||||
SelectorProjectItem() = default;
|
||||
SelectorProjectItem(Project *project) : m_project(project) {}
|
||||
Project *project() const { return m_project; }
|
||||
QString displayName() const
|
||||
{
|
||||
const auto hasSameProjectName = [this](TreeItem *ti) {
|
||||
return ti != this && static_cast<SelectorProjectItem *>(ti)->project()->displayName()
|
||||
== project()->displayName();
|
||||
};
|
||||
QString displayName = m_project->displayName();
|
||||
if (parent()->findAnyChild(hasSameProjectName)) {
|
||||
displayName.append(" (").append(project()->projectFilePath().toUserOutput())
|
||||
.append(')');
|
||||
}
|
||||
return displayName;
|
||||
}
|
||||
|
||||
private:
|
||||
QVariant data(int column, int role) const override
|
||||
{
|
||||
return column == 0 && role == Qt::DisplayRole ? displayName() : QString();
|
||||
}
|
||||
|
||||
Project *m_project = nullptr;
|
||||
};
|
||||
|
||||
class GenericItem : public TreeItem
|
||||
{
|
||||
public:
|
||||
GenericItem() = default;
|
||||
GenericItem(QObject *object) : m_object(object) {}
|
||||
QObject *object() const { return m_object; }
|
||||
QString displayName() const
|
||||
QString rawDisplayName() const
|
||||
{
|
||||
if (const auto p = qobject_cast<Project *>(object()))
|
||||
return p->displayName();
|
||||
if (const auto t = qobject_cast<Target *>(object()))
|
||||
return t->displayName();
|
||||
return static_cast<ProjectConfiguration *>(object())->displayName();
|
||||
|
||||
}
|
||||
QString displayName() const
|
||||
{
|
||||
if (const auto p = qobject_cast<Project *>(object())) {
|
||||
const auto hasSameProjectName = [this](TreeItem *ti) {
|
||||
return ti != this
|
||||
&& static_cast<GenericItem *>(ti)->rawDisplayName() == rawDisplayName();
|
||||
};
|
||||
QString displayName = p->displayName();
|
||||
if (parent()->findAnyChild(hasSameProjectName)) {
|
||||
displayName.append(" (").append(p->projectFilePath().toUserOutput())
|
||||
.append(')');
|
||||
}
|
||||
return displayName;
|
||||
}
|
||||
return rawDisplayName();
|
||||
}
|
||||
|
||||
private:
|
||||
QString toolTip() const
|
||||
QVariant toolTip() const
|
||||
{
|
||||
if (qobject_cast<Project *>(object()))
|
||||
return {};
|
||||
if (const auto t = qobject_cast<Target *>(object()))
|
||||
return t->toolTip();
|
||||
return static_cast<ProjectConfiguration *>(object())->toolTip();
|
||||
@@ -178,7 +145,8 @@ private:
|
||||
return displayName();
|
||||
case Qt::ToolTipRole:
|
||||
return toolTip();
|
||||
default:break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -186,131 +154,15 @@ private:
|
||||
QObject *m_object = nullptr;
|
||||
};
|
||||
|
||||
static QString rawDisplayName(const SelectorProjectItem *item)
|
||||
static bool compareItems(const TreeItem *ti1, const TreeItem *ti2)
|
||||
{
|
||||
return item->project()->displayName();
|
||||
}
|
||||
static QString rawDisplayName(const GenericItem *item) { return item->displayName(); }
|
||||
|
||||
template<typename T> bool compareItems(const TreeItem *ti1, const TreeItem *ti2)
|
||||
{
|
||||
const int result = caseFriendlyCompare(rawDisplayName(static_cast<const T*>(ti1)),
|
||||
rawDisplayName(static_cast<const T*>(ti2)));
|
||||
const int result = caseFriendlyCompare(static_cast<const GenericItem *>(ti1)->rawDisplayName(),
|
||||
static_cast<const GenericItem *>(ti2)->rawDisplayName());
|
||||
if (result != 0)
|
||||
return result < 0;
|
||||
return ti1 < ti2;
|
||||
}
|
||||
|
||||
class ProjectsModel : public TreeModel<SelectorProjectItem, SelectorProjectItem>
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ProjectsModel(QObject *parent) : TreeModel(parent)
|
||||
{
|
||||
connect(SessionManager::instance(), &SessionManager::projectAdded,
|
||||
this, [this](Project *project) {
|
||||
emit projectAdded(addItemForProject(project));
|
||||
});
|
||||
connect(SessionManager::instance(), &SessionManager::aboutToRemoveProject,
|
||||
this, [this](const Project *project) {
|
||||
SelectorProjectItem * const item = itemForProject(project);
|
||||
if (!item)
|
||||
return;
|
||||
destroyItem(item);
|
||||
emit optimalWidthChanged();
|
||||
});
|
||||
buildTree();
|
||||
}
|
||||
|
||||
SelectorProjectItem *itemForProject(const Project *project) const
|
||||
{
|
||||
return findItemAtLevel<1>([project](const SelectorProjectItem *item) {
|
||||
return item->project() == project;
|
||||
});
|
||||
}
|
||||
|
||||
signals:
|
||||
void projectAdded(const SelectorProjectItem *projectItem);
|
||||
void requestRestoreCurrentIndex();
|
||||
void optimalWidthChanged();
|
||||
|
||||
private:
|
||||
const SelectorProjectItem *addItemForProject(Project *project)
|
||||
{
|
||||
const auto projectItem = new SelectorProjectItem(project);
|
||||
rootItem()->insertOrderedChild(projectItem, &compareItems<SelectorProjectItem>);
|
||||
connect(project, &Project::displayNameChanged, this, [this] {
|
||||
rootItem()->sortChildren(&compareItems<SelectorProjectItem>);
|
||||
emit optimalWidthChanged();
|
||||
emit requestRestoreCurrentIndex();
|
||||
});
|
||||
return projectItem;
|
||||
}
|
||||
|
||||
void buildTree()
|
||||
{
|
||||
for (Project * const project : SessionManager::projects())
|
||||
addItemForProject(project);
|
||||
}
|
||||
};
|
||||
|
||||
class ProjectListView : public SelectorView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProjectListView(QWidget *parent = nullptr) : SelectorView(parent)
|
||||
{
|
||||
ProjectsModel * const model = new ProjectsModel(this);
|
||||
connect(model, &ProjectsModel::projectAdded, this,
|
||||
[this](const SelectorProjectItem *projectItem) {
|
||||
QFontMetrics fn(font());
|
||||
const int width = fn.horizontalAdvance(projectItem->displayName()) + padding();
|
||||
if (width > optimalWidth())
|
||||
setOptimalWidth(width);
|
||||
restoreCurrentIndex();
|
||||
});
|
||||
connect(model, &ProjectsModel::optimalWidthChanged,
|
||||
this, &ProjectListView::resetOptimalWidth);
|
||||
connect(model, &ProjectsModel::requestRestoreCurrentIndex,
|
||||
this, &ProjectListView::restoreCurrentIndex);
|
||||
connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
|
||||
this, [this, model](const Project *project) {
|
||||
const SelectorProjectItem * const item = model->itemForProject(project);
|
||||
if (item)
|
||||
setCurrentIndex(item->index());
|
||||
});
|
||||
setModel(model);
|
||||
connect(selectionModel(), &QItemSelectionModel::currentChanged,
|
||||
this, [model](const QModelIndex &index) {
|
||||
const SelectorProjectItem * const item = model->itemForIndex(index);
|
||||
if (item && item->project())
|
||||
SessionManager::setStartupProject(item->project());
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
ProjectsModel *theModel() const { return static_cast<ProjectsModel *>(model()); }
|
||||
|
||||
void restoreCurrentIndex()
|
||||
{
|
||||
const SelectorProjectItem * const itemForStartupProject
|
||||
= theModel()->itemForProject(SessionManager::startupProject());
|
||||
if (itemForStartupProject)
|
||||
setCurrentIndex(theModel()->indexForItem(itemForStartupProject));
|
||||
}
|
||||
|
||||
void resetOptimalWidth()
|
||||
{
|
||||
int width = 0;
|
||||
QFontMetrics fn(font());
|
||||
theModel()->forItemsAtLevel<1>([this, &width, &fn](const SelectorProjectItem *item) {
|
||||
width = qMax(fn.horizontalAdvance(item->displayName()) + padding(), width);
|
||||
});
|
||||
setOptimalWidth(width);
|
||||
}
|
||||
};
|
||||
|
||||
class GenericModel : public TreeModel<GenericItem, GenericItem>
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -327,8 +179,11 @@ public:
|
||||
const GenericItem *addItemForObject(QObject *object)
|
||||
{
|
||||
const auto item = new GenericItem(object);
|
||||
rootItem()->insertOrderedChild(item, &compareItems<GenericItem>);
|
||||
if (const auto target = qobject_cast<Target *>(object)) {
|
||||
rootItem()->insertOrderedChild(item, &compareItems);
|
||||
if (const auto project = qobject_cast<Project *>(object)) {
|
||||
connect(project, &Project::displayNameChanged,
|
||||
this, &GenericModel::displayNameChanged);
|
||||
} else if (const auto target = qobject_cast<Target *>(object)) {
|
||||
connect(target, &Target::kitChanged, this, &GenericModel::displayNameChanged);
|
||||
} else {
|
||||
const auto pc = qobject_cast<ProjectConfiguration *>(object);
|
||||
@@ -341,6 +196,13 @@ public:
|
||||
return item;
|
||||
}
|
||||
|
||||
GenericItem *itemForObject(const QObject *object) const
|
||||
{
|
||||
return findItemAtLevel<1>([object](const GenericItem *item) {
|
||||
return item->object() == object;
|
||||
});
|
||||
}
|
||||
|
||||
void setColumnCount(int columns) { m_columnCount = columns; }
|
||||
|
||||
signals:
|
||||
@@ -353,6 +215,99 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class SelectorView : public TreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SelectorView(QWidget *parent);
|
||||
|
||||
void setMaxCount(int maxCount);
|
||||
int maxCount();
|
||||
|
||||
int optimalWidth() const;
|
||||
void setOptimalWidth(int width);
|
||||
|
||||
int padding();
|
||||
|
||||
GenericModel *theModel() const { return static_cast<GenericModel *>(model()); }
|
||||
|
||||
protected:
|
||||
void resetOptimalWidth()
|
||||
{
|
||||
int width = 0;
|
||||
QFontMetrics fn(font());
|
||||
theModel()->forItemsAtLevel<1>([this, &width, &fn](const GenericItem *item) {
|
||||
width = qMax(fn.horizontalAdvance(item->displayName()) + padding(), width);
|
||||
});
|
||||
setOptimalWidth(width);
|
||||
}
|
||||
|
||||
private:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void keyReleaseEvent(QKeyEvent *event) override;
|
||||
|
||||
int m_maxCount = 0;
|
||||
int m_optimalWidth = 0;
|
||||
};
|
||||
|
||||
class ProjectListView : public SelectorView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProjectListView(QWidget *parent = nullptr) : SelectorView(parent)
|
||||
{
|
||||
const auto model = new GenericModel(this);
|
||||
model->rebuild(transform<QList<QObject *>>(SessionManager::projects(),
|
||||
[](Project *p) { return p; }));
|
||||
connect(SessionManager::instance(), &SessionManager::projectAdded,
|
||||
this, [this, model](Project *project) {
|
||||
const GenericItem *projectItem = model->addItemForObject(project);
|
||||
QFontMetrics fn(font());
|
||||
const int width = fn.horizontalAdvance(projectItem->displayName()) + padding();
|
||||
if (width > optimalWidth())
|
||||
setOptimalWidth(width);
|
||||
restoreCurrentIndex();
|
||||
});
|
||||
connect(SessionManager::instance(), &SessionManager::aboutToRemoveProject,
|
||||
this, [this, model](const Project *project) {
|
||||
GenericItem * const item = model->itemForObject(project);
|
||||
if (!item)
|
||||
return;
|
||||
model->destroyItem(item);
|
||||
resetOptimalWidth();
|
||||
});
|
||||
connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
|
||||
this, [this, model](const Project *project) {
|
||||
const GenericItem * const item = model->itemForObject(project);
|
||||
if (item)
|
||||
setCurrentIndex(item->index());
|
||||
});
|
||||
connect(model, &GenericModel::displayNameChanged, this, [this, model] {
|
||||
model->rootItem()->sortChildren(&compareItems);
|
||||
resetOptimalWidth();
|
||||
restoreCurrentIndex();
|
||||
});
|
||||
setModel(model);
|
||||
connect(selectionModel(), &QItemSelectionModel::currentChanged,
|
||||
this, [model](const QModelIndex &index) {
|
||||
const GenericItem * const item = model->itemForIndex(index);
|
||||
if (item && item->object())
|
||||
SessionManager::setStartupProject(qobject_cast<Project *>(item->object()));
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
void restoreCurrentIndex()
|
||||
{
|
||||
const GenericItem * const itemForStartupProject
|
||||
= theModel()->itemForObject(SessionManager::startupProject());
|
||||
if (itemForStartupProject)
|
||||
setCurrentIndex(theModel()->indexForItem(itemForStartupProject));
|
||||
}
|
||||
};
|
||||
|
||||
class GenericListWidget : public SelectorView
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -363,7 +318,7 @@ public:
|
||||
const auto model = new GenericModel(this);
|
||||
connect(model, &GenericModel::displayNameChanged, this, [this, model] {
|
||||
const GenericItem * const activeItem = model->itemForIndex(currentIndex());
|
||||
model->rootItem()->sortChildren(&compareItems<GenericItem>);
|
||||
model->rootItem()->sortChildren(&compareItems);
|
||||
resetOptimalWidth();
|
||||
if (activeItem)
|
||||
setCurrentIndex(activeItem->index());
|
||||
@@ -386,7 +341,7 @@ public:
|
||||
|
||||
void setActiveProjectConfiguration(QObject *active)
|
||||
{
|
||||
if (const GenericItem * const item = itemForObject(active))
|
||||
if (const GenericItem * const item = theModel()->itemForObject(active))
|
||||
setCurrentIndex(item->index());
|
||||
}
|
||||
|
||||
@@ -405,7 +360,7 @@ public:
|
||||
void removeProjectConfiguration(QObject *pc)
|
||||
{
|
||||
const auto activeItem = theModel()->itemForIndex(currentIndex());
|
||||
if (GenericItem * const item = itemForObject(pc)) {
|
||||
if (GenericItem * const item = theModel()->itemForObject(pc)) {
|
||||
theModel()->destroyItem(item);
|
||||
resetOptimalWidth();
|
||||
if (activeItem && activeItem != item)
|
||||
@@ -413,8 +368,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
GenericModel *theModel() const { return static_cast<GenericModel *>(model()); }
|
||||
|
||||
private:
|
||||
void mousePressEvent(QMouseEvent *event) override
|
||||
{
|
||||
@@ -442,23 +395,6 @@ private:
|
||||
TreeView::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
GenericItem *itemForObject(const QObject *object)
|
||||
{
|
||||
return theModel()->findItemAtLevel<1>([object](const GenericItem *item) {
|
||||
return item->object() == object;
|
||||
});
|
||||
}
|
||||
|
||||
void resetOptimalWidth()
|
||||
{
|
||||
int width = 0;
|
||||
QFontMetrics fn(font());
|
||||
theModel()->forItemsAtLevel<1>([this, &width, &fn](const GenericItem *item) {
|
||||
width = qMax(fn.horizontalAdvance(item->displayName()) + padding(), width);
|
||||
});
|
||||
setOptimalWidth(width);
|
||||
}
|
||||
|
||||
QObject *objectAt(const QModelIndex &index) const
|
||||
{
|
||||
return theModel()->itemForIndex(index)->object();
|
||||
|
Reference in New Issue
Block a user