diff --git a/common/lc_partselectionwidget.cpp b/common/lc_partselectionwidget.cpp index 06dc333f..c984750b 100644 --- a/common/lc_partselectionwidget.cpp +++ b/common/lc_partselectionwidget.cpp @@ -44,6 +44,10 @@ lcPartSelectionListModel::lcPartSelectionListModel(QObject* Parent) mListMode = lcGetProfileInt(LC_PROFILE_PARTS_LIST_LISTMODE); mShowDecoratedParts = lcGetProfileInt(LC_PROFILE_PARTS_LIST_DECORATED); mShowPartAliases = lcGetProfileInt(LC_PROFILE_PARTS_LIST_ALIASES); + mCaseSensitiveFilter = lcGetProfileInt(LC_PROFILE_PARTS_LIST_CASE_SENSITIVE_FILTER); + mFileNameFilter = lcGetProfileInt(LC_PROFILE_PARTS_LIST_FILE_NAME_FILTER); + mPartDescriptionFilter = lcGetProfileInt(LC_PROFILE_PARTS_LIST_PART_DESCRIPTION_FILTER); + mPartFilterType = static_cast(lcGetProfileInt(LC_PROFILE_PARTS_LIST_PART_FILTER)); int ColorCode = lcGetProfileInt(LC_PROFILE_PARTS_LIST_COLOR); if (ColorCode == -1) @@ -233,18 +237,30 @@ void lcPartSelectionListModel::SetFilter(const QString& Filter) { mFilter = Filter.toLatin1(); + bool DefaultFilter = mFileNameFilter && mPartDescriptionFilter; + bool WildcardFilter = mPartFilterType == lcPartFilterType::Wildcard; + bool FixedStringFilter = mPartFilterType == lcPartFilterType::FixedString; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + const QString Pattern = WildcardFilter ? QRegularExpression::wildcardToRegularExpression(mFilter) : mFilter; + QRegularExpression::PatternOption PatternOptions = mCaseSensitiveFilter ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption; + QRegularExpression FilterRx = QRegularExpression(Pattern, PatternOptions); +#else + Qt::CaseSensitivity CaseSensitive = mCaseSensitiveFilter ? Qt::CaseSensitive : Qt::CaseInsensitive; + QRegExp::PatternSyntax PatternSyntax = WildcardFilter ? QRegExp::Wildcard : QRegExp::RegExp2; + QRegExp FilterRx(mFilter, CaseSensitive, PatternSyntax); +#endif + for (size_t PartIdx = 0; PartIdx < mParts.size(); PartIdx++) { PieceInfo* Info = mParts[PartIdx].Info; - bool Visible; + bool Visible = true; if (!mShowDecoratedParts && Info->IsPatterned() && !Info->IsProjectPiece()) Visible = false; else if (!mShowPartAliases && Info->m_strDescription[0] == '=') Visible = false; - else if (mFilter.isEmpty()) - Visible = true; - else + else if (!mFilter.isEmpty()) { char Description[sizeof(Info->m_strDescription)]; char* Src = Info->m_strDescription; @@ -263,7 +279,28 @@ void lcPartSelectionListModel::SetFilter(const QString& Filter) Dst++; } - Visible = strcasestr(Description, mFilter) || strcasestr(Info->mFileName, mFilter); + if (FixedStringFilter) + { + if (DefaultFilter) + if (mCaseSensitiveFilter) + Visible = strstr(Description, mFilter) || strstr(Info->mFileName, mFilter); + else + Visible = strcasestr(Description, mFilter) || strcasestr(Info->mFileName, mFilter); + else if (mFileNameFilter) + Visible = mCaseSensitiveFilter ? strstr(Info->mFileName, mFilter) : strcasestr(Info->mFileName, mFilter); + else if (mPartDescriptionFilter) + Visible = mCaseSensitiveFilter ? strstr(Description, mFilter) : strcasestr(Description, mFilter); + } + else + { + if (DefaultFilter) + Visible = QString(Description).contains(FilterRx) || QString(Info->mFileName).contains(FilterRx); + else if (mFileNameFilter) + Visible = QString(Info->mFileName).contains(FilterRx); + else if (mPartDescriptionFilter) + Visible = QString(Description).contains(FilterRx); + } + } mListView->setRowHidden((int)PartIdx, !Visible); @@ -404,6 +441,46 @@ void lcPartSelectionListModel::SetShowPartAliases(bool Show) SetFilter(mFilter); } +void lcPartSelectionListModel::SetPartFilterType(lcPartFilterType Option) +{ + if (Option == mPartFilterType) + return; + + mPartFilterType = Option; + + SetFilter(mFilter); +} + +void lcPartSelectionListModel::SetCaseSensitiveFilter(bool Option) +{ + if (Option == mCaseSensitiveFilter) + return; + + mCaseSensitiveFilter = Option; + + SetFilter(mFilter); +} + +void lcPartSelectionListModel::SetFileNameFilter(bool Option) +{ + if (Option == mFileNameFilter) + return; + + mFileNameFilter = Option; + + SetFilter(mFilter); +} + +void lcPartSelectionListModel::SetPartDescriptionFilter(bool Option) +{ + if (Option == mPartDescriptionFilter) + return; + + mPartDescriptionFilter = Option; + + SetFilter(mFilter); +} + void lcPartSelectionListModel::SetIconSize(int Size) { if (Size == mIconSize) @@ -571,6 +648,48 @@ void lcPartSelectionListView::TogglePartAliases() lcSetProfileInt(LC_PROFILE_PARTS_LIST_ALIASES, Show); } +void lcPartSelectionListView::SetFixedStringFilter() +{ + SetPartFilterType(lcPartFilterType::FixedString); +} + +void lcPartSelectionListView::SetWildcardFilter() +{ + SetPartFilterType(lcPartFilterType::Wildcard); +} + +void lcPartSelectionListView::SetRegularExpressionFilter() +{ + SetPartFilterType(lcPartFilterType::RegularExpression); +} + +void lcPartSelectionListView::ToggleCaseSensitiveFilter() +{ + bool Option = !mListModel->GetCaseSensitiveFilter(); + mListModel->SetCaseSensitiveFilter(Option); + lcSetProfileInt(LC_PROFILE_PARTS_LIST_CASE_SENSITIVE_FILTER, Option); +} + +void lcPartSelectionListView::ToggleFileNameFilter() +{ + bool Option = !mListModel->GetFileNameFilter(); + mListModel->SetFileNameFilter(Option); + lcSetProfileInt(LC_PROFILE_PARTS_LIST_FILE_NAME_FILTER, Option); +} + +void lcPartSelectionListView::TogglePartDescriptionFilter() +{ + bool Option = !mListModel->GetPartDescriptionFilter(); + mListModel->SetPartDescriptionFilter(Option); + lcSetProfileInt(LC_PROFILE_PARTS_LIST_PART_DESCRIPTION_FILTER, Option); +} + +void lcPartSelectionListView::SetPartFilterType(lcPartFilterType Option) +{ + mListModel->SetPartFilterType(Option); + lcSetProfileInt(LC_PROFILE_PARTS_LIST_PART_FILTER, static_cast(Option)); +} + void lcPartSelectionListView::ToggleListMode() { mListModel->ToggleListMode(); @@ -973,6 +1092,39 @@ void lcPartSelectionWidget::OptionsMenuAboutToShow() FixedColor->setCheckable(true); FixedColor->setChecked(ListModel->IsColorLocked()); } + + Menu->addSeparator(); + + QActionGroup* FilterGroup = new QActionGroup(Menu); + + QAction* PartFilterType = Menu->addAction(tr("Fixed String"), mPartsWidget, SLOT(SetFixedStringFilter())); + PartFilterType->setCheckable(true); + PartFilterType->setChecked(ListModel->GetPartFilterType() == lcPartFilterType::FixedString); + FilterGroup->addAction(PartFilterType); + + QAction* WildcardFilter = Menu->addAction(tr("Wildcard"), mPartsWidget, SLOT(SetWildcardFilter())); + WildcardFilter->setCheckable(true); + WildcardFilter->setChecked(ListModel->GetPartFilterType() == lcPartFilterType::Wildcard); + FilterGroup->addAction(WildcardFilter); + + QAction* RegularExpressionFilter = Menu->addAction(tr("Regular Expression"), mPartsWidget, SLOT(SetRegularExpressionFilter())); + RegularExpressionFilter->setCheckable(true); + RegularExpressionFilter->setChecked(ListModel->GetPartFilterType() == lcPartFilterType::RegularExpression); + FilterGroup->addAction(RegularExpressionFilter); + + QAction* CaseSensitiveFilter = Menu->addAction(tr("Match Case"), mPartsWidget, SLOT(ToggleCaseSensitiveFilter())); + CaseSensitiveFilter->setCheckable(true); + CaseSensitiveFilter->setChecked(ListModel->GetCaseSensitiveFilter()); + + Menu->addSeparator(); + + QAction* FileNameFilter = Menu->addAction(tr("Part Name"), mPartsWidget, SLOT(ToggleFileNameFilter())); + FileNameFilter->setCheckable(true); + FileNameFilter->setChecked(ListModel->GetFileNameFilter()); + + QAction* PartDescriptionFilter = Menu->addAction(tr("Part Description"), mPartsWidget, SLOT(TogglePartDescriptionFilter())); + PartDescriptionFilter->setCheckable(true); + PartDescriptionFilter->setChecked(ListModel->GetPartDescriptionFilter()); } void lcPartSelectionWidget::EditPartPalettes() diff --git a/common/lc_partselectionwidget.h b/common/lc_partselectionwidget.h index c5e901bc..cf2221f3 100644 --- a/common/lc_partselectionwidget.h +++ b/common/lc_partselectionwidget.h @@ -22,6 +22,14 @@ enum class lcPartCategoryRole Index }; +enum class lcPartFilterType +{ + FixedString, + Wildcard, + RegularExpression, + Count +}; + struct lcPartPalette { QString Name; @@ -87,6 +95,26 @@ public: return mShowPartAliases; } + lcPartFilterType GetPartFilterType() const + { + return mPartFilterType; + } + + bool GetCaseSensitiveFilter() const + { + return mCaseSensitiveFilter; + } + + bool GetFileNameFilter() const + { + return mFileNameFilter; + } + + bool GetPartDescriptionFilter() const + { + return mPartDescriptionFilter; + } + int GetIconSize() const { return mIconSize; @@ -124,6 +152,10 @@ public: void RequestThumbnail(int PartIndex); void SetShowDecoratedParts(bool Show); void SetShowPartAliases(bool Show); + void SetPartFilterType(lcPartFilterType Option); + void SetCaseSensitiveFilter(bool Option); + void SetFileNameFilter(bool Option); + void SetPartDescriptionFilter(bool Option); void SetIconSize(int Size); void SetShowPartNames(bool Show); @@ -135,6 +167,7 @@ protected: lcPartSelectionListView* mListView; std::vector mParts; + lcPartFilterType mPartFilterType; int mIconSize; bool mColorLocked; int mColorIndex; @@ -142,6 +175,9 @@ protected: bool mListMode; bool mShowDecoratedParts; bool mShowPartAliases; + bool mCaseSensitiveFilter; + bool mFileNameFilter; + bool mPartDescriptionFilter; QByteArray mFilter; }; @@ -186,14 +222,21 @@ public slots: void SetMediumIcons(); void SetLargeIcons(); void SetExtraLargeIcons(); + void SetFixedStringFilter(); + void SetWildcardFilter(); + void SetRegularExpressionFilter(); void TogglePartNames(); void ToggleDecoratedParts(); void TogglePartAliases(); + void ToggleCaseSensitiveFilter(); + void ToggleFileNameFilter(); + void TogglePartDescriptionFilter(); void ToggleListMode(); void ToggleFixedColor(); protected: void SetIconSize(int Size); + void SetPartFilterType(lcPartFilterType Option); lcPartSelectionListModel* mListModel; lcPartSelectionWidget* mPartSelectionWidget; diff --git a/common/lc_profile.cpp b/common/lc_profile.cpp index bf975088..0cd93a7a 100644 --- a/common/lc_profile.cpp +++ b/common/lc_profile.cpp @@ -128,6 +128,10 @@ static lcProfileEntry gProfileEntries[LC_NUM_PROFILE_KEYS] = lcProfileEntry("Settings", "PartsListDecorated", 1), // LC_PROFILE_PARTS_LIST_DECORATED lcProfileEntry("Settings", "PartsListAliases", 1), // LC_PROFILE_PARTS_LIST_ALIASES lcProfileEntry("Settings", "PartsListListMode", 0), // LC_PROFILE_PARTS_LIST_LISTMODE + lcProfileEntry("Settings", "PartsListPartFilter", 0), // LC_PROFILE_PARTS_LIST_PART_FILTER + lcProfileEntry("Settings", "PartsListCaseSensitiveFilter", 0), // LC_PROFILE_PARTS_LIST_CASE_SENSITIVE_FILTER + lcProfileEntry("Settings", "PartsListFileNameFilter", 1), // LC_PROFILE_PARTS_LIST_FILE_NAME_FILTER + lcProfileEntry("Settings", "PartsListPartDescriptionFilter", 1), // LC_PROFILE_PARTS_LIST_PART_DESCRIPTION_FILTER lcProfileEntry("Settings", "StudStyle", 0), // LC_PROFILE_STUD_STYLE lcProfileEntry("Defaults", "Author", ""), // LC_PROFILE_DEFAULT_AUTHOR_NAME diff --git a/common/lc_profile.h b/common/lc_profile.h index b91df8ea..135c79f2 100644 --- a/common/lc_profile.h +++ b/common/lc_profile.h @@ -75,6 +75,10 @@ enum LC_PROFILE_KEY LC_PROFILE_PARTS_LIST_DECORATED, LC_PROFILE_PARTS_LIST_ALIASES, LC_PROFILE_PARTS_LIST_LISTMODE, + LC_PROFILE_PARTS_LIST_PART_FILTER, + LC_PROFILE_PARTS_LIST_CASE_SENSITIVE_FILTER, + LC_PROFILE_PARTS_LIST_FILE_NAME_FILTER, + LC_PROFILE_PARTS_LIST_PART_DESCRIPTION_FILTER, LC_PROFILE_STUD_STYLE, // Defaults for new projects.