Commit 89c51c8b authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle

Update bin filtering to use more standard button, allow filtering on multiple criterias

parent 6f221df9
Pipeline #13048 passed with stage
in 13 minutes and 52 seconds
......@@ -783,6 +783,8 @@ Bin::Bin(std::shared_ptr<ProjectItemModel> model, QWidget *parent)
, m_propertiesPanel(nullptr)
, m_blankThumb()
, m_filterGroup(this)
, m_filterRateGroup(this)
, m_filterTypeGroup(this)
, m_invalidClipDialog(nullptr)
, m_gainedFocus(false)
, m_audioDuration(0)
......@@ -989,29 +991,98 @@ Bin::Bin(std::shared_ptr<ProjectItemModel> model, QWidget *parent)
});
// Filter menu
m_filterGroup.setExclusive(false);
m_filterMenu = new QMenu(i18n("Filter"), this);
m_filterButton = new QToolButton;
m_filterButton->setPopupMode(QToolButton::MenuButtonPopup);
m_filterButton->setCheckable(true);
m_filterButton->setPopupMode(QToolButton::MenuButtonPopup);
m_filterButton->setIcon(QIcon::fromTheme(QStringLiteral("view-filter")));
m_filterButton->setToolTip(i18n("Filter"));
m_filterButton->setStyleSheet(QString("QToolButton:checked{ background-color: %1;border: none; border-radius: 2px;padding-right: 20px;}").arg(palette().highlight().color().name()));
m_filterButton->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
m_filterButton->setMenu(m_filterMenu);
connect(m_filterButton, &QToolButton::toggled, [&](bool toggled) {
if (toggled) {
processBinFiltering();
connect(m_filterButton, &QToolButton::toggled, [this] (bool toggle) {
if (!toggle) {
m_proxyModel->slotClearSearchFilters();
return;
}
QList<QAction *> list = m_filterMenu->actions();
int rateFilters = 0;
int typeFilters = 0;
QStringList tagFilters;
for (QAction *ac : list) {
if (ac->isChecked()) {
QString actionData = ac->data().toString();
if (actionData.startsWith(QLatin1Char('#'))) {
// Filter by tag
tagFilters << actionData;
} else if (actionData.startsWith(QLatin1Char('.'))) {
// Filter by rating
rateFilters = actionData.remove(0, 1).toInt();
}
}
}
// Type actions
list = m_filterTypeGroup.actions();
for (QAction *ac : list) {
if (ac->isChecked()) {
typeFilters = ac->data().toInt();
break;
}
}
QSignalBlocker bkt(m_filterButton);
if (rateFilters > 0 || !tagFilters.isEmpty() ||typeFilters > 0) {
m_filterButton->setChecked(true);
} else {
// Reset filter
m_proxyModel->slotClearSearchType();
m_filterButton->setChecked(false);
}
m_proxyModel->slotSetFilters(tagFilters, rateFilters, typeFilters);
});
connect(m_filterMenu, &QMenu::triggered, [&] () {
if (m_filterButton->isChecked()) {
processBinFiltering();
} else {
connect(m_filterMenu, &QMenu::triggered, [this](QAction *action) {
if (action->data().toString().isEmpty()) {
// Clear filters action
QSignalBlocker bk(m_filterMenu);
QList<QAction *> list = m_filterMenu->actions();
list << m_filterTypeGroup.actions();
for (QAction *ac : list) {
ac->setChecked(false);
}
m_proxyModel->slotClearSearchFilters();
m_filterButton->setChecked(false);
return;
}
QList<QAction *> list = m_filterMenu->actions();
int rateFilters = 0;
int typeFilters = 0;
QStringList tagFilters;
for (QAction *ac : list) {
if (ac->isChecked()) {
QString actionData = ac->data().toString();
if (actionData.startsWith(QLatin1Char('#'))) {
// Filter by tag
tagFilters << actionData;
} else if (actionData.startsWith(QLatin1Char('.'))) {
// Filter by rating
rateFilters = actionData.remove(0, 1).toInt();
}
}
}
// Type actions
list = m_filterTypeGroup.actions();
for (QAction *ac : list) {
if (ac->isChecked()) {
typeFilters = ac->data().toInt();
break;
}
}
QSignalBlocker bkt(m_filterButton);
if (rateFilters > 0 || !tagFilters.isEmpty() ||typeFilters > 0) {
m_filterButton->setChecked(true);
} else {
m_filterButton->setChecked(false);
}
m_proxyModel->slotSetFilters(tagFilters, rateFilters, typeFilters);
});
m_tagAction->setCheckable(true);
......@@ -1116,28 +1187,6 @@ void Bin::abortOperations()
blockSignals(false);
}
void Bin::processBinFiltering()
{
if (m_filterGroup.checkedAction()) {
QString actionData = m_filterGroup.checkedAction()->data().toString();
if (actionData.startsWith(QLatin1Char('#'))) {
// Filter by tag
m_proxyModel->slotSetSearchTag(actionData);
} else if (actionData.startsWith(QLatin1Char('.'))) {
// Filter by rating
int type = actionData.remove(0, 1).toInt();
m_proxyModel->slotSetSearchRating(type);
} else {
// Filter by type
int type = actionData.toInt();
m_proxyModel->slotSetSearchType(type);
}
m_filterButton->setToolTip(i18n("Filter by %1", m_filterGroup.checkedAction()->text().remove(QLatin1Char('&'))));
} else {
emit displayBinMessage(i18n("Select a filter to apply in filter menu"), KMessageWidget::Information);
}
}
bool Bin::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonRelease) {
......@@ -1486,6 +1535,8 @@ void Bin::rebuildFilters(QMap <QString, QString> tags)
{
m_filterMenu->clear();
// Add tag filters
QAction *clearFilter = new QAction(QIcon::fromTheme(QStringLiteral("edit-clear")), i18n("Clear filters"), this);
m_filterMenu->addAction(clearFilter);
int tagsCount = tags.size();
for (int i = 1; i <= tagsCount; i++) {
QAction *tag = pCore->window()->actionCollection()->action(QString("tag_%1").arg(i));
......@@ -1500,7 +1551,7 @@ void Bin::rebuildFilters(QMap <QString, QString> tags)
m_filterMenu->addSeparator();
QAction *rateFilter;
for (int i = 1; i< 6; ++i) {
rateFilter = new QAction(QIcon::fromTheme(QStringLiteral("favorite")), i18np("%1 star", "%1 stars", i), &m_filterGroup);
rateFilter = new QAction(QIcon::fromTheme(QStringLiteral("favorite")), i18np("%1 star", "%1 stars", i), &m_filterRateGroup);
rateFilter->setData(QString(".%1").arg(2 * i));
rateFilter->setCheckable(true);
m_filterMenu->addAction(rateFilter);
......@@ -1508,42 +1559,42 @@ void Bin::rebuildFilters(QMap <QString, QString> tags)
// Add type filters
m_filterMenu->addSeparator();
QMenu *typeMenu = new QMenu(i18n("Sort by type"), m_filterMenu);
QMenu *typeMenu = new QMenu(i18n("Filter by type"), m_filterMenu);
m_filterMenu->addMenu(typeMenu);
m_filterMenu->addSeparator();
QAction *typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("video-x-generic")), i18n("AV Clip"), &m_filterGroup);
QAction *typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("video-x-generic")), i18n("AV Clip"), &m_filterTypeGroup);
typeFilter->setData(ClipType::AV);
typeFilter->setCheckable(true);
typeMenu->addAction(typeFilter);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("video-x-matroska")), i18n("Mute Video"), &m_filterGroup);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("video-x-matroska")), i18n("Mute Video"), &m_filterTypeGroup);
typeFilter->setData(ClipType::Video);
typeFilter->setCheckable(true);
typeMenu->addAction(typeFilter);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("audio-x-generic")), i18n("Audio"), &m_filterGroup);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("audio-x-generic")), i18n("Audio"), &m_filterTypeGroup);
typeFilter->setData(ClipType::Audio);
typeFilter->setCheckable(true);
typeMenu->addAction(typeFilter);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("image-jpeg")), i18n("Image"), &m_filterGroup);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("image-jpeg")), i18n("Image"), &m_filterTypeGroup);
typeFilter->setData(ClipType::Image);
typeFilter->setCheckable(true);
typeMenu->addAction(typeFilter);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-add-slide-clip")), i18n("Slideshow"), &m_filterGroup);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-add-slide-clip")), i18n("Slideshow"), &m_filterTypeGroup);
typeFilter->setData(ClipType::SlideShow);
typeFilter->setCheckable(true);
typeMenu->addAction(typeFilter);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("video-mlt-playlist")), i18n("Playlist"), &m_filterGroup);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("video-mlt-playlist")), i18n("Playlist"), &m_filterTypeGroup);
typeFilter->setData(ClipType::Playlist);
typeFilter->setCheckable(true);
typeMenu->addAction(typeFilter);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("draw-text")), i18n("Title"), &m_filterGroup);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("draw-text")), i18n("Title"), &m_filterTypeGroup);
typeFilter->setData(ClipType::Text);
typeFilter->setCheckable(true);
typeMenu->addAction(typeFilter);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("draw-text")), i18n("Title Template"), &m_filterGroup);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("draw-text")), i18n("Title Template"), &m_filterTypeGroup);
typeFilter->setData(ClipType::TextTemplate);
typeFilter->setCheckable(true);
typeMenu->addAction(typeFilter);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-add-color-clip")), i18n("Color"), &m_filterGroup);
typeFilter = new QAction(QIcon::fromTheme(QStringLiteral("kdenlive-add-color-clip")), i18n("Color"), &m_filterTypeGroup);
typeFilter->setData(ClipType::Color);
typeFilter->setCheckable(true);
typeMenu->addAction(typeFilter);
......
......@@ -436,6 +436,8 @@ private:
TagWidget *m_tagsWidget;
QMenu *m_filterMenu;
QActionGroup m_filterGroup;
QActionGroup m_filterRateGroup;
QActionGroup m_filterTypeGroup;
QToolButton *m_filterButton;
/** @brief The info widget for failed jobs. */
KMessageWidget *m_infoMessage;
......@@ -463,8 +465,6 @@ private:
void showSlideshowWidget(const std::shared_ptr<ProjectClip> &clip);
void processAudioThumbs();
void updateSortingAction(int ix);
/** @brief Apply Bin filtering. */
void processBinFiltering();
int wheelAccumulatedDelta;
signals:
......
......@@ -73,8 +73,10 @@ bool ProjectSortProxyModel::filterAcceptsRowItself(int sourceRow, const QModelIn
// Column 4 contains the item tag data
QModelIndex indexTag = sourceModel()->index(sourceRow, 4, sourceParent);
auto tagData = sourceModel()->data(indexTag);
if (!tagData.toString().contains(m_searchTag, Qt::CaseInsensitive)) {
return false;
for (const QString &tag : m_searchTag) {
if (!tagData.toString().contains(tag, Qt::CaseInsensitive)) {
return false;
}
}
}
if (data.toString().contains(m_searchString, Qt::CaseInsensitive)) {
......@@ -140,31 +142,15 @@ void ProjectSortProxyModel::slotSetSearchString(const QString &str)
invalidateFilter();
}
void ProjectSortProxyModel::slotSetSearchRating(const int type)
{
m_searchTag.clear();
m_searchType = 0;
m_searchRating = type;
invalidateFilter();
}
void ProjectSortProxyModel::slotSetSearchTag(const QString &str)
void ProjectSortProxyModel::slotSetFilters(const QStringList tagFilters, const int rateFilters, const int typeFilters)
{
m_searchType = 0;
m_searchRating = 0;
m_searchTag = str;
invalidateFilter();
}
void ProjectSortProxyModel::slotSetSearchType(const int type)
{
m_searchTag.clear();
m_searchRating = 0;
m_searchType = type;
m_searchType = typeFilters;
m_searchRating = rateFilters;
m_searchTag = tagFilters;
invalidateFilter();
}
void ProjectSortProxyModel::slotClearSearchType()
void ProjectSortProxyModel::slotClearSearchFilters()
{
m_searchTag.clear();
m_searchRating = 0;
......
......@@ -44,13 +44,9 @@ public slots:
/** @brief Set search string that will filter the view */
void slotSetSearchString(const QString &str);
/** @brief Set search tag that will filter the view */
void slotSetSearchTag(const QString &str);
/** @brief Set search rating that will filter the view */
void slotSetSearchRating(const int type);
/** @brief Set search type that will filter the view */
void slotSetSearchType(const int type);
void slotSetFilters(const QStringList tagFilters, int rateFilters, int typeFilters);
/** @brief Reset search filters */
void slotClearSearchType();
void slotClearSearchFilters();
/** @brief Relay datachanged signal from view's model */
void slotDataChanged(const QModelIndex &ix1, const QModelIndex &ix2, const QVector<int> &roles);
/** @brief Select all items in model */
......@@ -72,7 +68,7 @@ protected:
private:
QItemSelectionModel *m_selection;
QString m_searchString;
QString m_searchTag;
QStringList m_searchTag;
int m_searchType;
int m_searchRating;
QCollator m_collator;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment