From b45faa2e73ba7a39a9df7e283bb9fdbc72b460e0 Mon Sep 17 00:00:00 2001 From: mappu Date: Sun, 23 Jun 2024 15:28:15 +1200 Subject: [PATCH] main: add nav context menu, support closing open connections --- db_badger.go | 5 ++++ db_bolt.go | 5 ++++ db_none.go | 2 ++ db_redis.go | 5 ++++ db_sqlite.go | 5 ++++ loadedDatabase.go | 1 + main.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 81 insertions(+) diff --git a/db_badger.go b/db_badger.go index 4bd38b0..2cacab9 100644 --- a/db_badger.go +++ b/db_badger.go @@ -108,6 +108,11 @@ func (ld *badgerLoadedDatabase) ExecQuery(query string, resultArea *vcl.TListVie vcl.ShowMessage("Badger doesn't support querying") } +func (ld *badgerLoadedDatabase) Close() { + _ = ld.db.Close() + ld.arena = nil +} + var _ loadedDatabase = &badgerLoadedDatabase{} // interface assertion // diff --git a/db_bolt.go b/db_bolt.go index 0f774c3..fb35a8e 100644 --- a/db_bolt.go +++ b/db_bolt.go @@ -98,6 +98,11 @@ func (ld *boltLoadedDatabase) ExecQuery(query string, resultArea *vcl.TListView) vcl.ShowMessage("Bolt doesn't support querying") } +func (ld *boltLoadedDatabase) Close() { + _ = ld.db.Close() + ld.arena = nil +} + var _ loadedDatabase = &boltLoadedDatabase{} // interface assertion // diff --git a/db_none.go b/db_none.go index f2ddaf5..037450b 100644 --- a/db_none.go +++ b/db_none.go @@ -33,3 +33,5 @@ func (n *noLoadedDatabase) NavChildren(ndata *navData) ([]string, error) { func (n *noLoadedDatabase) Keepalive(ndata *navData) { } + +func (n *noLoadedDatabase) Close() {} diff --git a/db_redis.go b/db_redis.go index 7947700..e4be5c8 100644 --- a/db_redis.go +++ b/db_redis.go @@ -150,6 +150,11 @@ func (ld *redisLoadedDatabase) ExecQuery(query string, resultArea *vcl.TListView fmt.Printf("result\n%#v\n", ret) } +func (ld *redisLoadedDatabase) Close() { + _ = ld.db.Close() + ld.arena = nil +} + var _ loadedDatabase = &redisLoadedDatabase{} // interface assertion // diff --git a/db_sqlite.go b/db_sqlite.go index 48eee47..59b9f9c 100644 --- a/db_sqlite.go +++ b/db_sqlite.go @@ -230,6 +230,11 @@ func (ld *sqliteLoadedDatabase) NavChildren(ndata *navData) ([]string, error) { return nil, fmt.Errorf("unknown nav path %#v", ndata.bucketPath) } +func (ld *sqliteLoadedDatabase) Close() { + _ = ld.db.Close() + ld.arena = nil +} + var _ loadedDatabase = &sqliteLoadedDatabase{} // interface assertion // diff --git a/loadedDatabase.go b/loadedDatabase.go index 49d5027..bcc6829 100644 --- a/loadedDatabase.go +++ b/loadedDatabase.go @@ -13,6 +13,7 @@ type loadedDatabase interface { ExecQuery(query string, resultArea *vcl.TListView) NavChildren(ndata *navData) ([]string, error) Keepalive(ndata *navData) + Close() } // navData is the .Data() pointer for each TTreeNode in the left-hand tree. diff --git a/main.go b/main.go index b92dbff..b0ef795 100644 --- a/main.go +++ b/main.go @@ -115,6 +115,7 @@ func (f *TMainForm) OnFormCreate(sender vcl.IObject) { f.Buckets.SetReadOnly(true) // prevent click to rename on nodes f.Buckets.SetOnExpanding(f.OnNavExpanding) f.Buckets.SetOnChange(f.OnNavChange) + f.Buckets.SetOnContextPopup(f.OnNavContextPopup) hsplit := vcl.NewSplitter(f) hsplit.SetParent(f) @@ -262,6 +263,63 @@ func (f *TMainForm) OnMnuFileExitClick(sender vcl.IObject) { f.Close() } +func (f *TMainForm) OnNavContextPopup(sender vcl.IObject, mousePos types.TPoint, handled *bool) { + *handled = true + + curItem := f.Buckets.Selected() + if curItem == nil { + // Nothing is selected at all + return + } + + mnu := vcl.NewPopupMenu(f.Buckets) + + mnuRefresh := vcl.NewMenuItem(mnu) + mnuRefresh.SetCaption("Refresh") + mnuRefresh.SetOnClick(f.OnNavContextRefresh) + mnu.Items().Add(mnuRefresh) + + // Check what custom actions the ndata->db itself wants to add + // ... + + if curItem.Parent() == nil { + // Top-level item (database connection). Allow closing by right-click. + mnuSep := vcl.NewMenuItem(mnu) + mnuSep.SetCaption("-") + mnu.Items().Add(mnuSep) + + mnuClose := vcl.NewMenuItem(mnu) + mnuClose.SetCaption("Close") + mnuClose.SetOnClick(f.OnNavContextClose) + mnu.Items().Add(mnuClose) + } + + // Show popup + mnu.Popup2() +} + +func (f *TMainForm) OnNavContextRefresh(sender vcl.IObject) { + vcl.ShowMessage("TODO") + // TODO +} + +func (f *TMainForm) OnNavContextClose(sender vcl.IObject) { + curItem := f.Buckets.Selected() + if curItem == nil { + return // Nothing selected (shouldn't happen) + } + if curItem.Parent() != nil { + return // Selection is not top-level DB connection (shouldn't happen) + } + + ndata := (*navData)(curItem.Data()) + + ndata.ld.Close() + curItem.Delete() + + // n.b. This triggers OnNavChange, which will then re-render from noLoadedDatabase{} +} + func (f *TMainForm) OnQueryExecute(sender vcl.IObject) { // If query tab is not selected, switch to it, but do not exec if f.Tabs.ActivePageIndex() != 2 {