Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: filter by key/type #2

Merged
merged 3 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
### Features

- [x] Find by keyword
- [ ] Filter by Key
- [ ] Filter by Type
- [x] Filter by Key
- [x] Filter by Type
- [x] Double-clicked to open target registry in `Regedit`


### TODO

- Making all features useable
- Improving resource usage and performance
- Improving UI to show value exactly the same we see in `Regedit`

Expand Down
248 changes: 221 additions & 27 deletions gui/gui.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const (
APP_HEIGHT int = 800

DEBOUNCE_INTERVAL time.Duration = 250 * time.Millisecond
UPDATE_INTERVAL time.Duration = 500 * time.Millisecond
UPDATE_INTERVAL time.Duration = 250 * time.Millisecond

COL_TITLE_PATH string = "Path"
COL_TITLE_NAME string = "Name"
Expand All @@ -42,27 +42,49 @@ type AppWindow struct {
showedResultMu sync.Mutex
updateShowed chan bool

debounce *time.Timer
debounceMu sync.Mutex
debounce *time.Timer
debounceMu sync.Mutex

keywordChan chan string

keyChan chan string
keyEnabledChan chan bool
filterKeyEnabled bool

typeChan chan string
typeEnabledChan chan bool
filterTypeEnabled bool

*walk.MainWindow
searchBox *walk.LineEdit

// TODO filters by key and type
// keyCheckBox *walk.CheckBox
// typeCheckBox *walk.CheckBox
// keyComboBox *walk.ComboBox
// typeComboBox *walk.ComboBox
keyCheckBox *walk.CheckBox
typeCheckBox *walk.CheckBox
keyComboBox *walk.ComboBox
typeComboBox *walk.ComboBox

regKeyModel *[]string
regTypeModel *[]string

resultTable *walk.TableView
regTableModel *models.RegistryTableModel
}

func NewAppWindow(usecase usecases.RegistryUsecase) (*AppWindow, error) {

app := &AppWindow{usecase: usecase, collectedResult: make([]*entities.Registry, 0), showedResult: make([]*entities.Registry, 0),
regTableModel: models.NewRegistryTableModel(), keywordChan: make(chan string), updateShowed: make(chan bool)}
app := &AppWindow{usecase: usecase,
collectedResult: make([]*entities.Registry, 0), showedResult: make([]*entities.Registry, 0),
regTableModel: models.NewRegistryTableModel(), updateShowed: make(chan bool),
keywordChan: make(chan string),
keyEnabledChan: make(chan bool),
typeEnabledChan: make(chan bool),
keyChan: make(chan string),
typeChan: make(chan string),
filterKeyEnabled: false,
filterTypeEnabled: false,
regKeyModel: models.NewRegistryKeyModel(),
regTypeModel: models.NewRegistryTypeModel(),
}

var icon, _ = walk.NewIconFromResourceId(2)

Expand All @@ -78,12 +100,54 @@ func NewAppWindow(usecase usecases.RegistryUsecase) (*AppWindow, error) {
},

Children: []Widget{

LineEdit{
AssignTo: &app.searchBox,
OnTextChanged: func() {
go app.handleOnKeywordChanged()
},
},

Composite{
Layout: HBox{},
Children: []Widget{
CheckBox{
AssignTo: &app.keyCheckBox,
Text: "Filter Key",
TextOnLeftSide: true,
OnClicked: func() {
app.onFilterKeyChecked()
},
},
ComboBox{
AssignTo: &app.keyComboBox,
Editable: false,
Model: *app.regKeyModel,
CurrentIndex: 0,
OnCurrentIndexChanged: func() {
app.onFilterKeyChanged()
},
},
CheckBox{
AssignTo: &app.typeCheckBox,
Text: "Filter Type",
TextOnLeftSide: true,
OnClicked: func() {
app.onFilterTypeChecked()
},
},
ComboBox{
AssignTo: &app.typeComboBox,
Editable: false,
Model: *app.regTypeModel,
CurrentIndex: 0,
OnCurrentIndexChanged: func() {
app.onFilterTypeChanged()
},
},
},
},

TableView{
AssignTo: &app.resultTable,
AlternatingRowBG: true,
Expand Down Expand Up @@ -125,49 +189,96 @@ func (app *AppWindow) streamingRegistry() {
}
}

// TODO find better way
func (app *AppWindow) processingShowResult() {

var prevKeyword string = ""
var currKeyword string = ""
var currKeyword string
var currKeyEnabled bool
var currTypeEnabled bool
var currKey string
var currType string

for {
updateAndFilter := func(forceUpdate bool) {

select {
case newKeyword := <-app.keywordChan:
if newKeyword != currKeyword {
prevKeyword = currKeyword
currKeyword = newKeyword
}
case <-time.After(UPDATE_INTERVAL):
}

go func(keyword string) {
go func(keyword string, keyEnabled bool, typeEnabled bool, filterKey, filterType string) {

app.collectedResultMu.Lock()
collectedCopy := make([]*entities.Registry, len(app.collectedResult))
copy(collectedCopy, app.collectedResult)
app.collectedResultMu.Unlock()

filtered := make([]*entities.Registry, 0, len(collectedCopy))

for _, reg := range collectedCopy {
if app.usecase.FilterByKeyword(reg, keyword) {
filtered = append(filtered, reg)
if keyEnabled && !typeEnabled && app.usecase.FilterByKey(reg, filterKey) {
filtered = append(filtered, reg)
} else if typeEnabled && !keyEnabled && app.usecase.FilterByType(reg, filterType) {
filtered = append(filtered, reg)
} else if keyEnabled && typeEnabled && app.usecase.FilterByKey(reg, filterKey) && app.usecase.FilterByType(reg, filterType) {
filtered = append(filtered, reg)
} else if !keyEnabled && !typeEnabled {
filtered = append(filtered, reg)
}
}
}

app.showedResultMu.Lock()
app.showedResult = filtered
app.showedResultMu.Unlock()

if prevKeyword != keyword {
if forceUpdate {
select {
case app.updateShowed <- true:
prevKeyword = keyword
default:
}
}

}(currKeyword)
}(currKeyword, currKeyEnabled, currTypeEnabled, currKey, currType)

}

for {

select {

case newKeyword := <-app.keywordChan:
if newKeyword != currKeyword {
currKeyword = newKeyword
updateAndFilter(true)
}

case newKeyEnabled := <-app.keyEnabledChan:
if newKeyEnabled != currKeyEnabled {
currKeyEnabled = newKeyEnabled
updateAndFilter(true)
}

case newTypeEnabled := <-app.typeEnabledChan:
if newTypeEnabled != currTypeEnabled {
currTypeEnabled = newTypeEnabled
updateAndFilter(true)
}

case newKey := <-app.keyChan:
if newKey != currKey {
currKey = newKey
if currKeyEnabled {
updateAndFilter(true)
}
}

case newType := <-app.typeChan:
if newType != currType {
currType = newType
if currTypeEnabled {
updateAndFilter(true)
}
}

case <-time.After(UPDATE_INTERVAL):
updateAndFilter(false)
}

}

Expand Down Expand Up @@ -253,3 +364,86 @@ func (app *AppWindow) handleOnSizeChanged() {
})

}

func (app *AppWindow) onFilterKeyChecked() {

app.debounceMu.Lock()
defer app.debounceMu.Unlock()

if app.debounce != nil {
app.debounce.Stop()
}

app.debounce = time.AfterFunc(0, func() {
app.filterKeyEnabled = !app.filterKeyEnabled
app.keyCheckBox.SetChecked(app.filterKeyEnabled)
select {
case app.keyEnabledChan <- app.filterKeyEnabled:
filterKey := app.keyComboBox.Text()
app.keyChan <- filterKey
default:
}
})

}

func (app *AppWindow) onFilterKeyChanged() {

filterKey := app.keyComboBox.Text()

app.debounceMu.Lock()
defer app.debounceMu.Unlock()

if app.debounce != nil {
app.debounce.Stop()
}

app.debounce = time.AfterFunc(0, func() {
select {
case app.keyChan <- filterKey:
default:
}
})

}

func (app *AppWindow) onFilterTypeChecked() {

app.debounceMu.Lock()
defer app.debounceMu.Unlock()

if app.debounce != nil {
app.debounce.Stop()
}

app.debounce = time.AfterFunc(0, func() {
app.filterTypeEnabled = !app.filterTypeEnabled
app.typeCheckBox.SetChecked(app.filterTypeEnabled)
select {
case app.typeEnabledChan <- app.filterTypeEnabled:
filterType := app.typeComboBox.Text()
app.typeChan <- filterType
default:
}
})
}

func (app *AppWindow) onFilterTypeChanged() {

filterType := app.typeComboBox.Text()

app.debounceMu.Lock()
defer app.debounceMu.Unlock()

if app.debounce != nil {
app.debounce.Stop()
}

app.debounce = time.AfterFunc(0, func() {
select {
case app.typeChan <- filterType:
default:
}
})

}
10 changes: 10 additions & 0 deletions gui/models/registryKey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package models

import "github.com/0736b/registry-finder-gui/utils"

var registryKeyModel []string = []string{utils.STR_HKEY_CLASSES_ROOT, utils.STR_HKEY_CURRENT_USER, utils.STR_HKEY_LOCAL_MACHINE, utils.STR_HKEY_USERS, utils.STR_HKEY_CURRENT_CONFIG}

func NewRegistryKeyModel() *[]string {

return &registryKeyModel
}
12 changes: 12 additions & 0 deletions gui/models/registryType.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package models

import "github.com/0736b/registry-finder-gui/utils"

var registryTypeModel []string = []string{utils.STR_NONE, utils.STR_REG_SZ, utils.STR_REG_EXPAND_SZ, utils.STR_REG_BINARY, utils.STR_REG_DWORD,
utils.STR_REG_DWORD_BIG_ENDIAN, utils.STR_REG_LINK, utils.STR_REG_MULTI_SZ, utils.STR_REG_RESOURCE_LIST, utils.STR_REG_FULL_RESOURCE_DESCRIPTOR,
utils.STR_REG_RESOURCE_REQUIREMENTS_LIST, utils.STR_REG_QWORD}

func NewRegistryTypeModel() *[]string {

return &registryTypeModel
}
4 changes: 2 additions & 2 deletions usecases/registryUsecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ func (u *RegistryUsecaseImpl) FilterByKeyword(reg *entities.Registry, keyword st

func (u *RegistryUsecaseImpl) FilterByKey(reg *entities.Registry, filterKey string) bool {

return true
return strings.HasPrefix(reg.Path, filterKey)
}

func (u *RegistryUsecaseImpl) FilterByType(reg *entities.Registry, filterType string) bool {

return true
return reg.Type == filterType
}

func (u *RegistryUsecaseImpl) OpenInRegedit(reg *entities.Registry) {
Expand Down
Loading