mirror of
https://github.com/aclist/dztui.git
synced 2026-08-29 03:06:56 +02:00
feat: atomic maps per server context
This commit is contained in:
parent
82c585a195
commit
7e6013bdbd
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,7 +1,5 @@
|
|||||||
## Added
|
## Added
|
||||||
- Add pyproject.toml file
|
- Add pyproject.toml file
|
||||||
- requests, packaging.version, psutil
|
|
||||||
- Lockfile
|
|
||||||
- Changelog text wrapping and formatting
|
- Changelog text wrapping and formatting
|
||||||
- Decouple UI components into modules
|
- Decouple UI components into modules
|
||||||
- Choose from kilometer or miles distance display
|
- Choose from kilometer or miles distance display
|
||||||
@ -17,26 +15,31 @@
|
|||||||
- Integrate add/connect widgets into main menu
|
- Integrate add/connect widgets into main menu
|
||||||
- Favorite/connect/LAN panels integrated with server views
|
- Favorite/connect/LAN panels integrated with server views
|
||||||
- Colorized IP/ID validation
|
- Colorized IP/ID validation
|
||||||
|
- Copy favorite server IP to clipboard
|
||||||
|
- Set favorite server from tables
|
||||||
|
- Detailed/copyable trace in critical error dialogs
|
||||||
- Visual icons
|
- Visual icons
|
||||||
- Integrated server notebook
|
- Integrated server notebook
|
||||||
- Retain position on servers
|
|
||||||
- Propagate width changes to all tables
|
- Propagate width changes to all tables
|
||||||
- Remember tree position in menus
|
- Remember tree position in menus
|
||||||
|
- Show hidden server count after filtering
|
||||||
|
- Atomic map filters per server context
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
- Reduce padding on keys button
|
- Reduce padding on keys button
|
||||||
- Boldface breadcrumbs
|
- Boldface breadcrumbs
|
||||||
- Bold labels inside frames
|
- Bold labels inside frames
|
||||||
- Unsticky keys when clicking sidebar
|
- Sidebar buttos do not steal focus
|
||||||
- Copy IP copies IP:queryport only instead of IP:gameport:queryport, mimics syntax needed by add by ip method
|
- Copy IP copies IP:queryport only instead of IP:gameport:queryport, mimics syntax needed by add by ip method
|
||||||
|
- Load new model into view without flushing
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
- Longstanding issue with left clicks not registering as tree selection changes after spamming keyboard input
|
- Longstanding issue with left clicks not registering as tree selection changes after spamming keyboard input
|
||||||
- Rare segfaults when changing maps (threading)
|
- Rare segfaults when changing maps (threading)
|
||||||
|
- Moved dialogs out of threads
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
- Setup wizard
|
- Setup wizard
|
||||||
- Copy favorite server IP to clipboard
|
|
||||||
- Set favorite server from tables
|
|
||||||
- Detailed/copyable trace in critical error dialogs
|
|
||||||
- Local documentation
|
- Local documentation
|
||||||
|
- Offline mods
|
||||||
|
- Move debug mode to developers only
|
||||||
|
|||||||
@ -3,6 +3,7 @@ from typing import Union, TYPE_CHECKING
|
|||||||
import gi
|
import gi
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
|
from gi.repository.Gtk import ListStore
|
||||||
from gi.repository import Gdk, GObject # noqa E402
|
from gi.repository import Gdk, GObject # noqa E402
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -86,14 +87,14 @@ class Emitter(GObject.GObject):
|
|||||||
def servers_loaded(self, tag: "ServerTab") -> None:
|
def servers_loaded(self, tag: "ServerTab") -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# @GObject.Signal(
|
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
|
||||||
# flags=GObject.SignalFlags.RUN_LAST,
|
def servers_loaded_init(self) -> None:
|
||||||
# arg_types=(
|
pass
|
||||||
# object,
|
|
||||||
# object,
|
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(str,))
|
||||||
# ),
|
def map_selection_changed(self, map: str) -> None:
|
||||||
# )
|
pass
|
||||||
# def distcalc_ended(
|
|
||||||
# self, dist: Union[str, None], context: Union["ServerTab", "NotebookPage"]
|
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(object,))
|
||||||
# ) -> None:
|
def load_maps(self, store: ListStore) -> None:
|
||||||
# pass
|
pass
|
||||||
|
|||||||
@ -94,6 +94,7 @@ class Controller(GObject.GObject):
|
|||||||
|
|
||||||
self.model_man = ModelManager()
|
self.model_man = ModelManager()
|
||||||
self.emitter = Emitter()
|
self.emitter = Emitter()
|
||||||
|
self.emitter.connect("map_selection_changed", self._on_map_selection_changed)
|
||||||
|
|
||||||
# NOTE: suppress requests until entire UI is loaded
|
# NOTE: suppress requests until entire UI is loaded
|
||||||
self.loaded = False
|
self.loaded = False
|
||||||
@ -235,6 +236,7 @@ class Controller(GObject.GObject):
|
|||||||
c = self.mediator.statusbar.statusbar.get_context_id(context)
|
c = self.mediator.statusbar.statusbar.get_context_id(context)
|
||||||
self.mediator.statusbar.statusbar.pop(c)
|
self.mediator.statusbar.statusbar.pop(c)
|
||||||
|
|
||||||
|
# TODO:
|
||||||
@deprecated("use set_by_context")
|
@deprecated("use set_by_context")
|
||||||
def set_statusbar(self, text: str, context: str) -> int:
|
def set_statusbar(self, text: str, context: str) -> int:
|
||||||
msg_id = self.mediator.statusbar.set_text(text, context)
|
msg_id = self.mediator.statusbar.set_text(text, context)
|
||||||
@ -350,7 +352,6 @@ class Controller(GObject.GObject):
|
|||||||
self.open_page(button.opens)
|
self.open_page(button.opens)
|
||||||
|
|
||||||
def dump_api(self) -> None:
|
def dump_api(self) -> None:
|
||||||
self.first_iteration = True
|
|
||||||
key = self.query_config(Preferences.STEAM)
|
key = self.query_config(Preferences.STEAM)
|
||||||
job = Servers.query_api
|
job = Servers.query_api
|
||||||
params = Servers.params
|
params = Servers.params
|
||||||
@ -379,7 +380,6 @@ class Controller(GObject.GObject):
|
|||||||
|
|
||||||
# TODO: additional ping column pass, collated
|
# TODO: additional ping column pass, collated
|
||||||
parsed = Servers.parse_json(serv)
|
parsed = Servers.parse_json(serv)
|
||||||
self.new_maps = parsed
|
|
||||||
self.push_data(parsed, FilterMode.INITIAL, success=True)
|
self.push_data(parsed, FilterMode.INITIAL, success=True)
|
||||||
|
|
||||||
def get_help_row(self) -> str:
|
def get_help_row(self) -> str:
|
||||||
@ -608,17 +608,17 @@ class Controller(GObject.GObject):
|
|||||||
import time
|
import time
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
data = (
|
data = (
|
||||||
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False],
|
["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False],
|
||||||
["BAR", "a", "a", "a", 1, 1, 1, "172.111.51.156:2302", 1, 1, "a", False],
|
["BAR", "chernarusplus", "a", "a", 1, 1, 1, "172.111.51.156:2302", 1, 1, "a", False],
|
||||||
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False],
|
["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False],
|
||||||
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False],
|
["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False],
|
||||||
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
||||||
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
||||||
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
||||||
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
||||||
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
||||||
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
||||||
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
|
||||||
)
|
)
|
||||||
self.push_data(data, FilterMode.INITIAL, success=True)
|
self.push_data(data, FilterMode.INITIAL, success=True)
|
||||||
|
|
||||||
@ -629,21 +629,25 @@ class Controller(GObject.GObject):
|
|||||||
treeview = self.get_active_treeview()
|
treeview = self.get_active_treeview()
|
||||||
treeview.set_loaded(True)
|
treeview.set_loaded(True)
|
||||||
treeview.set_model(self.to_insert)
|
treeview.set_model(self.to_insert)
|
||||||
|
map_man = treeview.get_map_man()
|
||||||
|
|
||||||
# TODO: signals or other approach to deferring map
|
# TODO: signals or other approach to deferring map
|
||||||
# model insertion after thread closes
|
# model insertion after thread closes
|
||||||
# cf. servers_loaded signal
|
# cf. servers_loaded signal
|
||||||
|
|
||||||
# CHORE: this is placeholder logic
|
|
||||||
if self.first_iteration:
|
|
||||||
self.mediator.filters.set_unique_maps(self.new_maps)
|
|
||||||
self.first_iteration = False
|
|
||||||
|
|
||||||
context = self.get_active_context()
|
context = self.get_active_context()
|
||||||
self.emitter.emit("servers_loaded", context)
|
self.emitter.emit("servers_loaded", context)
|
||||||
|
|
||||||
|
# CHORE: this is placeholder logic
|
||||||
|
if self.first_iteration:
|
||||||
|
map_man.set_unique_maps(self.new_maps)
|
||||||
|
self.emitter.emit("servers_loaded_init")
|
||||||
|
self.first_iteration = False
|
||||||
|
self.new_maps = None
|
||||||
|
|
||||||
|
|
||||||
treeview.grab_focus()
|
treeview.grab_focus()
|
||||||
# TODO: chiefly responsible for removing spinner dialog
|
|
||||||
self.destroy_on_idle()
|
self.destroy_on_idle()
|
||||||
#if self.success is False:
|
#if self.success is False:
|
||||||
# # TODO: different dialogs for server tab contexts, e.g. lan timeout
|
# # TODO: different dialogs for server tab contexts, e.g. lan timeout
|
||||||
@ -655,13 +659,15 @@ class Controller(GObject.GObject):
|
|||||||
# TODO: what if refresh action occurred, and the old model is valid?
|
# TODO: what if refresh action occurred, and the old model is valid?
|
||||||
treeview = self.get_active_treeview()
|
treeview = self.get_active_treeview()
|
||||||
treeview.set_model(None)
|
treeview.set_model(None)
|
||||||
|
map_man = treeview.get_map_man()
|
||||||
# TODO: disable map, keyword, and filter widgets if model is None?
|
# TODO: disable map, keyword, and filter widgets if model is None?
|
||||||
# -> signal driven (servers_empty)
|
# -> signal driven (servers_empty)
|
||||||
# would have to make those unsensitive when changing server tabs
|
# would have to make those unsensitive when changing server tabs
|
||||||
# if model is not None when changing tab, emit other signal
|
# if model is not None when changing tab, emit other signal
|
||||||
self.mediator.filters.set_unique_maps(None)
|
map_man.set_unique_maps(None)
|
||||||
|
|
||||||
context = self.get_active_context()
|
context = self.get_active_context()
|
||||||
|
# TODO: distinguish signals, e.g. "servers_failed_to_load"
|
||||||
self.emitter.emit("servers_loaded", context)
|
self.emitter.emit("servers_loaded", context)
|
||||||
treeview.grab_focus()
|
treeview.grab_focus()
|
||||||
self.destroy_on_idle()
|
self.destroy_on_idle()
|
||||||
@ -693,6 +699,10 @@ class Controller(GObject.GObject):
|
|||||||
manager.set_control(data)
|
manager.set_control(data)
|
||||||
manager.filter(mode)
|
manager.filter(mode)
|
||||||
self.to_insert = manager.get_model()
|
self.to_insert = manager.get_model()
|
||||||
|
# TODO: pre parse maps
|
||||||
|
u_maps = set([row[1] for row in data])
|
||||||
|
self.new_maps = sorted(u_maps)
|
||||||
|
|
||||||
treeview.set_loaded(True)
|
treeview.set_loaded(True)
|
||||||
GLib.idle_add(self.cleanup)
|
GLib.idle_add(self.cleanup)
|
||||||
|
|
||||||
@ -714,6 +724,9 @@ class Controller(GObject.GObject):
|
|||||||
self.callback = {"func": callback, "args": args}
|
self.callback = {"func": callback, "args": args}
|
||||||
|
|
||||||
def destroy_on_idle(self) -> None:
|
def destroy_on_idle(self) -> None:
|
||||||
|
"""
|
||||||
|
TODO: chiefly responsible for removing spinner dialog
|
||||||
|
"""
|
||||||
self.wait_dialog.destroy()
|
self.wait_dialog.destroy()
|
||||||
func = self.get_callback()
|
func = self.get_callback()
|
||||||
self.mediator.window.set_sensitive(True)
|
self.mediator.window.set_sensitive(True)
|
||||||
@ -790,7 +803,8 @@ class Controller(GObject.GObject):
|
|||||||
def get_player_count(self) -> str:
|
def get_player_count(self) -> str:
|
||||||
treeview = self.get_active_treeview()
|
treeview = self.get_active_treeview()
|
||||||
model = treeview.get_model()
|
model = treeview.get_model()
|
||||||
control_model = treeview.filter_man.get_control()
|
filter_man = treeview.get_filter_man()
|
||||||
|
control_model = filter_man.get_control()
|
||||||
count = format_player_count(model, control_model)
|
count = format_player_count(model, control_model)
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@ -804,13 +818,16 @@ class Controller(GObject.GObject):
|
|||||||
@call_on_thread(strings.dialog.filtering)
|
@call_on_thread(strings.dialog.filtering)
|
||||||
def filter_threaded(self, mode: FilterMode, label: str) -> None:
|
def filter_threaded(self, mode: FilterMode, label: str) -> None:
|
||||||
tv = self.get_active_treeview()
|
tv = self.get_active_treeview()
|
||||||
tv.filter_man.filter(mode, label)
|
filter_man = tv.get_filter_man()
|
||||||
|
filter_man.filter(mode, label)
|
||||||
self.push_data("", mode, success=True)
|
self.push_data("", mode, success=True)
|
||||||
|
|
||||||
# FIXME: optional label/map/keyword parameter
|
# FIXME: optional label/map/keyword parameter
|
||||||
|
# FIXME: drop set_callback
|
||||||
def refilter_model(self, mode: FilterMode, label: Optional[str] = None) -> None:
|
def refilter_model(self, mode: FilterMode, label: Optional[str] = None) -> None:
|
||||||
tv = self.get_active_treeview()
|
tv = self.get_active_treeview()
|
||||||
if tv.filter_man.get_control() is None:
|
filter_man = tv.get_filter_man()
|
||||||
|
if filter_man.get_control() is None:
|
||||||
return
|
return
|
||||||
# TODO: deprecated in this context?
|
# TODO: deprecated in this context?
|
||||||
self.set_callback(None, None)
|
self.set_callback(None, None)
|
||||||
@ -827,10 +844,12 @@ class Controller(GObject.GObject):
|
|||||||
func = treeview.get_query_func()
|
func = treeview.get_query_func()
|
||||||
if func is None:
|
if func is None:
|
||||||
self.emitter.emit("servers_loaded", treeview.get_enum())
|
self.emitter.emit("servers_loaded", treeview.get_enum())
|
||||||
|
treeview.set_model(None)
|
||||||
return
|
return
|
||||||
# TODO:
|
# TODO:
|
||||||
# manager = treeview.get_filter_man()
|
# manager = treeview.get_filter_man()
|
||||||
# manager.clear_model()
|
# manager.clear_model()
|
||||||
|
self.first_iteration = True
|
||||||
self.set_callback(None, None)
|
self.set_callback(None, None)
|
||||||
self.run_query_func(func)
|
self.run_query_func(func)
|
||||||
|
|
||||||
@ -850,9 +869,6 @@ class Controller(GObject.GObject):
|
|||||||
def get_help_store(self) -> Gtk.ListStore:
|
def get_help_store(self) -> Gtk.ListStore:
|
||||||
return self.model_man.get_help_store()
|
return self.model_man.get_help_store()
|
||||||
|
|
||||||
def get_map_store(self) -> Gtk.ListStore:
|
|
||||||
return self.model_man.get_map_store()
|
|
||||||
|
|
||||||
def get_modlist_store(self) -> Gtk.ListStore:
|
def get_modlist_store(self) -> Gtk.ListStore:
|
||||||
return self.model_man.get_modlist_store()
|
return self.model_man.get_modlist_store()
|
||||||
|
|
||||||
@ -865,11 +881,31 @@ class Controller(GObject.GObject):
|
|||||||
def get_filters(self) -> list:
|
def get_filters(self) -> list:
|
||||||
return self.mediator.filters.get_filters()
|
return self.mediator.filters.get_filters()
|
||||||
|
|
||||||
|
# TODO: filterman calls back to here, gets convoluted
|
||||||
def get_keyword(self) -> str:
|
def get_keyword(self) -> str:
|
||||||
return self.mediator.filters.get_keyword_filter()
|
return self.mediator.filters.get_keyword_filter()
|
||||||
|
|
||||||
def get_map(self) -> str:
|
def get_map_store(self) -> Gtk.ListStore:
|
||||||
return self.mediator.filters.get_selected_map()
|
treeview = self.get_active_treeview()
|
||||||
|
map_man = treeview.get_map_man()
|
||||||
|
return map_man.get_map_store()
|
||||||
|
|
||||||
|
def get_selected_map(self) -> str:
|
||||||
|
treeview = self.get_active_treeview()
|
||||||
|
map_man = treeview.get_map_man()
|
||||||
|
return map_man.get_selected_map()
|
||||||
|
|
||||||
def get_prior_map(self) -> str:
|
def get_prior_map(self) -> str:
|
||||||
return self.mediator.filters.get_prior_map()
|
treeview = self.get_active_treeview()
|
||||||
|
map_man = treeview.get_map_man()
|
||||||
|
return map_man.get_prior_map()
|
||||||
|
|
||||||
|
def _on_map_selection_changed(self, emitter: Emitter, selection: str) -> None:
|
||||||
|
treeview = self.get_active_treeview()
|
||||||
|
map_man = treeview.get_map_man()
|
||||||
|
map_man.set_selected_map(selection)
|
||||||
|
self.refilter_model(FilterMode.MAP)
|
||||||
|
|
||||||
|
def has_server_model(self) -> bool:
|
||||||
|
treeview = self.get_active_treeview()
|
||||||
|
return treeview.get_model() is not None
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
## Added
|
## Added
|
||||||
- Add pyproject.toml file
|
- Add pyproject.toml file
|
||||||
- requests, packaging.version, psutil
|
|
||||||
- Lockfile
|
|
||||||
- Changelog text wrapping and formatting
|
- Changelog text wrapping and formatting
|
||||||
- Decouple UI components into modules
|
- Decouple UI components into modules
|
||||||
- Choose from kilometer or miles distance display
|
- Choose from kilometer or miles distance display
|
||||||
@ -17,26 +15,31 @@
|
|||||||
- Integrate add/connect widgets into main menu
|
- Integrate add/connect widgets into main menu
|
||||||
- Favorite/connect/LAN panels integrated with server views
|
- Favorite/connect/LAN panels integrated with server views
|
||||||
- Colorized IP/ID validation
|
- Colorized IP/ID validation
|
||||||
|
- Copy favorite server IP to clipboard
|
||||||
|
- Set favorite server from tables
|
||||||
|
- Detailed/copyable trace in critical error dialogs
|
||||||
- Visual icons
|
- Visual icons
|
||||||
- Integrated server notebook
|
- Integrated server notebook
|
||||||
- Retain position on servers
|
|
||||||
- Propagate width changes to all tables
|
- Propagate width changes to all tables
|
||||||
- Remember tree position in menus
|
- Remember tree position in menus
|
||||||
|
- Show hidden server count after filtering
|
||||||
|
- Atomic map filters per server context
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
- Reduce padding on keys button
|
- Reduce padding on keys button
|
||||||
- Boldface breadcrumbs
|
- Boldface breadcrumbs
|
||||||
- Bold labels inside frames
|
- Bold labels inside frames
|
||||||
- Unsticky keys when clicking sidebar
|
- Sidebar buttos do not steal focus
|
||||||
- Copy IP copies IP:queryport only instead of IP:gameport:queryport, mimics syntax needed by add by ip method
|
- Copy IP copies IP:queryport only instead of IP:gameport:queryport, mimics syntax needed by add by ip method
|
||||||
|
- Load new model into view without flushing
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
- Longstanding issue with left clicks not registering as tree selection changes after spamming keyboard input
|
- Longstanding issue with left clicks not registering as tree selection changes after spamming keyboard input
|
||||||
- Rare segfaults when changing maps (threading)
|
- Rare segfaults when changing maps (threading)
|
||||||
|
- Moved dialogs out of threads
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
- Setup wizard
|
- Setup wizard
|
||||||
- Copy favorite server IP to clipboard
|
|
||||||
- Set favorite server from tables
|
|
||||||
- Detailed/copyable trace in critical error dialogs
|
|
||||||
- Local documentation
|
- Local documentation
|
||||||
|
- Offline mods
|
||||||
|
- Move debug mode to developers only
|
||||||
|
|||||||
@ -47,7 +47,8 @@ class FilteredModelManager:
|
|||||||
self.filter_cache = {}
|
self.filter_cache = {}
|
||||||
self.ping_cache: dict[str, int] = {}
|
self.ping_cache: dict[str, int] = {}
|
||||||
|
|
||||||
self.ephemeral_model = self.new_model_from_class(ServerColumns)
|
self.ephemeral_model: ListStore = None
|
||||||
|
#= self.new_model_from_class(ServerColumns)
|
||||||
|
|
||||||
self.control_model: list = None
|
self.control_model: list = None
|
||||||
self.filtered: list = None
|
self.filtered: list = None
|
||||||
@ -107,13 +108,14 @@ class FilteredModelManager:
|
|||||||
if row[7] in self.ping_cache:
|
if row[7] in self.ping_cache:
|
||||||
row[9] = self.ping_cache[row[7]]
|
row[9] = self.ping_cache[row[7]]
|
||||||
|
|
||||||
|
clone = self.new_model_from_class(ServerColumns)
|
||||||
if len(rows) > 0:
|
if len(rows) > 0:
|
||||||
clone = self.new_model_from_class(ServerColumns)
|
|
||||||
rows = self.sort_rows(rows)
|
rows = self.sort_rows(rows)
|
||||||
for row in rows:
|
for row in rows:
|
||||||
clone.append(row)
|
clone.append(row)
|
||||||
else:
|
#else:
|
||||||
clone = None
|
# print("nothing to filter, sending none")
|
||||||
|
# clone = None
|
||||||
|
|
||||||
self.set_cache(filters, clone, rows)
|
self.set_cache(filters, clone, rows)
|
||||||
self.set_model(clone)
|
self.set_model(clone)
|
||||||
@ -136,7 +138,7 @@ class FilteredModelManager:
|
|||||||
Multi-filtration for any context starts by narrowing by map
|
Multi-filtration for any context starts by narrowing by map
|
||||||
"""
|
"""
|
||||||
rows = self.filtered
|
rows = self.filtered
|
||||||
sel_map = self.controller.get_map()
|
sel_map = self.controller.get_selected_map()
|
||||||
|
|
||||||
if sel_map == strings.all_maps:
|
if sel_map == strings.all_maps:
|
||||||
return rows
|
return rows
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import gi
|
|||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository.Gtk import ListStore # noqa E402
|
from gi.repository.Gtk import ListStore # noqa E402
|
||||||
from gi.repository import GLib, GObject, Gtk # noqa E402
|
from gi.repository import GObject, Gtk # noqa E402
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True, frozen=True)
|
@dataclass(slots=True, frozen=True)
|
||||||
|
|||||||
@ -55,16 +55,18 @@ def format_player_count(model: Gtk.TreeModel | None, control: list) -> str:
|
|||||||
players = 0
|
players = 0
|
||||||
hits: int
|
hits: int
|
||||||
status: str
|
status: str
|
||||||
if model is None or len(model) == 0:
|
if model is None:
|
||||||
return no_servers
|
return no_servers
|
||||||
else:
|
else:
|
||||||
hits = len(model)
|
hits = len(model)
|
||||||
for row in model:
|
for row in model:
|
||||||
players += row[4]
|
players += row[4]
|
||||||
control_total = len(control)
|
control_total = len(control)
|
||||||
|
hits_pretty = pluralize("matches", hits)
|
||||||
players_pretty = pluralize("players", players)
|
players_pretty = pluralize("players", players)
|
||||||
control_pretty = pluralize("matches", control_total)
|
hidden = control_total - hits
|
||||||
status = f"Showing {hits:n}/{control_total:n} {control_pretty} with {players:n} {players_pretty}"
|
hidden_pretty = f" ({hidden:n} hidden)" if hidden > 0 else ""
|
||||||
|
status = f"Showing {hits:n} {hits_pretty}{hidden_pretty}, {players:n} {players_pretty}."
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -167,7 +167,7 @@ ping_tooltip = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# statusbar_helptext = "Select a row to see its detailed description"
|
# statusbar_helptext = "Select a row to see its detailed description"
|
||||||
statusbar_helptext = "No server metadata to list."
|
#statusbar_helptext = "No server metadata to list."
|
||||||
|
|
||||||
# use e.g. filters.1pp
|
# use e.g. filters.1pp
|
||||||
filter_1pp = "1PP"
|
filter_1pp = "1PP"
|
||||||
|
|||||||
@ -17,6 +17,7 @@ logger = logging.getLogger(__name__)
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dzgui.controllers.mc import Controller
|
from dzgui.controllers.mc import Controller
|
||||||
from dzgui.controllers.emitter import Emitter
|
from dzgui.controllers.emitter import Emitter
|
||||||
|
from dzgui.const.enum import ServerTab
|
||||||
|
|
||||||
|
|
||||||
class FilterPanel(Gtk.Box):
|
class FilterPanel(Gtk.Box):
|
||||||
@ -49,10 +50,10 @@ class FilterPanel(Gtk.Box):
|
|||||||
|
|
||||||
self.enabled_filters = dict(self.default_filters)
|
self.enabled_filters = dict(self.default_filters)
|
||||||
self.keyword_filter = ""
|
self.keyword_filter = ""
|
||||||
self.selected_map: str = strings.all_maps
|
#self.selected_map: str = strings.all_maps
|
||||||
self.prior_map: str = strings.all_maps
|
#self.prior_map: str = strings.all_maps
|
||||||
|
|
||||||
button_grid = Gtk.Grid(
|
self.button_grid = Gtk.Grid(
|
||||||
halign=Gtk.Align.CENTER, column_spacing=5, column_homogeneous=True
|
halign=Gtk.Align.CENTER, column_spacing=5, column_homogeneous=True
|
||||||
)
|
)
|
||||||
row = 1
|
row = 1
|
||||||
@ -70,7 +71,7 @@ class FilterPanel(Gtk.Box):
|
|||||||
if col > 3:
|
if col > 3:
|
||||||
row += 1
|
row += 1
|
||||||
col = 1
|
col = 1
|
||||||
button_grid.attach(checkbox, col, row, 1, 1)
|
self.button_grid.attach(checkbox, col, row, 1, 1)
|
||||||
|
|
||||||
checkbox.connect("toggled", self._on_check_toggled)
|
checkbox.connect("toggled", self._on_check_toggled)
|
||||||
self.checks.append(checkbox)
|
self.checks.append(checkbox)
|
||||||
@ -103,6 +104,8 @@ class FilterPanel(Gtk.Box):
|
|||||||
"request_maps_focus", lambda _: self.maps_entry.grab_focus()
|
"request_maps_focus", lambda _: self.maps_entry.grab_focus()
|
||||||
)
|
)
|
||||||
self.emitter.connect("check_button_pressed", self.toggle_check_by_key)
|
self.emitter.connect("check_button_pressed", self.toggle_check_by_key)
|
||||||
|
self.emitter.connect("servers_loaded", self._on_servers_loaded)
|
||||||
|
self.emitter.connect("load_maps", self._on_maps_loaded)
|
||||||
|
|
||||||
completion = Gtk.EntryCompletion(inline_completion=True)
|
completion = Gtk.EntryCompletion(inline_completion=True)
|
||||||
completion.set_text_column(0)
|
completion.set_text_column(0)
|
||||||
@ -123,26 +126,22 @@ class FilterPanel(Gtk.Box):
|
|||||||
self.maps_combo.connect("changed", self._on_map_changed)
|
self.maps_combo.connect("changed", self._on_map_changed)
|
||||||
self.maps_combo.connect("key-press-event", self._on_combo_keypress)
|
self.maps_combo.connect("key-press-event", self._on_combo_keypress)
|
||||||
|
|
||||||
for el in self.filters_label, self.keyword_entry, self.maps_combo, button_grid:
|
for el in self.filters_label, self.keyword_entry, self.maps_combo, self.button_grid:
|
||||||
self.pack_start(el, NO_EXPAND, NO_FILL, NO_PADDING)
|
self.pack_start(el, NO_EXPAND, NO_FILL, NO_PADDING)
|
||||||
|
|
||||||
def set_unique_maps(self, maps: list) -> None:
|
def _on_servers_loaded(self, emitter: "Emitter", tab: "ServerTab") -> None:
|
||||||
if maps is None:
|
state = self.controller.has_server_model()
|
||||||
return
|
for widget in (self.keyword_entry, self.maps_combo, self.button_grid):
|
||||||
if len(maps) < 1:
|
widget.set_sensitive(state)
|
||||||
return
|
|
||||||
u_maps = set([row[1] for row in maps])
|
def _on_maps_loaded(self, emitter: "Emitter", store: Gtk.ListStore) -> None:
|
||||||
u_maps = sorted(u_maps)
|
self.maps_combo.set_model(store)
|
||||||
self.controller.append_map([strings.all_maps])
|
|
||||||
self.selected_map = strings.all_maps
|
|
||||||
for m in u_maps:
|
|
||||||
self.controller.append_map([m])
|
|
||||||
self.maps_hr.append(m)
|
|
||||||
self.maps_combo.set_active(0)
|
self.maps_combo.set_active(0)
|
||||||
|
|
||||||
def get_filters(self) -> tuple:
|
def get_filters(self) -> tuple:
|
||||||
|
selected = self.controller.get_selected_map()
|
||||||
filters = []
|
filters = []
|
||||||
filters.append(self.selected_map)
|
filters.append(selected)
|
||||||
filters.append(self.keyword_filter)
|
filters.append(self.keyword_filter)
|
||||||
for k in self.enabled_filters:
|
for k in self.enabled_filters:
|
||||||
if not self.enabled_filters[k]:
|
if not self.enabled_filters[k]:
|
||||||
@ -205,8 +204,9 @@ class FilterPanel(Gtk.Box):
|
|||||||
def _on_map_completion(self, entry, editable):
|
def _on_map_completion(self, entry, editable):
|
||||||
text = entry.get_text()
|
text = entry.get_text()
|
||||||
completion = entry.get_completion()
|
completion = entry.get_completion()
|
||||||
|
store = self.controller.get_map_store()
|
||||||
if len(text) >= completion.get_minimum_key_length():
|
if len(text) >= completion.get_minimum_key_length():
|
||||||
completion.set_model(self.map_store)
|
completion.set_model(store)
|
||||||
|
|
||||||
def restore_focus_to_treeview(self) -> Literal[False]:
|
def restore_focus_to_treeview(self) -> Literal[False]:
|
||||||
view = self.controller.get_active_treeview()
|
view = self.controller.get_active_treeview()
|
||||||
@ -232,15 +232,6 @@ class FilterPanel(Gtk.Box):
|
|||||||
case _:
|
case _:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_prior_map(self, mapname: str) -> None:
|
|
||||||
self.prior_map = mapname
|
|
||||||
|
|
||||||
def get_prior_map(self) -> str:
|
|
||||||
return self.prior_map
|
|
||||||
|
|
||||||
def get_selected_map(self) -> str:
|
|
||||||
return self.selected_map
|
|
||||||
|
|
||||||
def get_keyword_filter(self) -> str:
|
def get_keyword_filter(self) -> str:
|
||||||
return self.keyword_filter
|
return self.keyword_filter
|
||||||
|
|
||||||
@ -293,7 +284,6 @@ class FilterPanel(Gtk.Box):
|
|||||||
check.set_active(not state)
|
check.set_active(not state)
|
||||||
|
|
||||||
def _on_check_toggled(self, button: Gtk.CheckButton) -> None:
|
def _on_check_toggled(self, button: Gtk.CheckButton) -> None:
|
||||||
# treeview = self.controller.get_active_treeview()
|
|
||||||
label = button.get_label()
|
label = button.get_label()
|
||||||
state = button.get_active()
|
state = button.get_active()
|
||||||
logger.info(f"User toggled button '{label}' to {state}")
|
logger.info(f"User toggled button '{label}' to {state}")
|
||||||
@ -306,7 +296,7 @@ class FilterPanel(Gtk.Box):
|
|||||||
self.controller.refilter_model(mode, label)
|
self.controller.refilter_model(mode, label)
|
||||||
|
|
||||||
def _on_map_changed(self, combo: Gtk.ComboBox) -> None:
|
def _on_map_changed(self, combo: Gtk.ComboBox) -> None:
|
||||||
old_sel = self.selected_map
|
old_sel = self.controller.get_selected_map()
|
||||||
model = combo.get_model()
|
model = combo.get_model()
|
||||||
tree_iter = combo.get_active_iter()
|
tree_iter = combo.get_active_iter()
|
||||||
if tree_iter is None:
|
if tree_iter is None:
|
||||||
@ -317,7 +307,5 @@ class FilterPanel(Gtk.Box):
|
|||||||
if not selection:
|
if not selection:
|
||||||
return
|
return
|
||||||
logger.info(f"User selected map '{selection}'")
|
logger.info(f"User selected map '{selection}'")
|
||||||
self.prior_map = self.selected_map
|
|
||||||
self.selected_map = selection
|
|
||||||
self.maps_entry.set_text(selection)
|
self.maps_entry.set_text(selection)
|
||||||
self.controller.refilter_model(FilterMode.MAP)
|
self.emitter.emit("map_selection_changed", selection)
|
||||||
|
|||||||
@ -112,7 +112,7 @@ class Statusbar(Gtk.Grid):
|
|||||||
self.set_by_context(context, pretty)
|
self.set_by_context(context, pretty)
|
||||||
|
|
||||||
def append_distance(self, dist: str) -> str:
|
def append_distance(self, dist: str) -> str:
|
||||||
return f"{self.playercount} | Distance: {dist}"
|
return f"{self.playercount} Distance: {dist}"
|
||||||
|
|
||||||
def _on_servers_loaded(self, statusbar: Self, context: "ServerTab") -> None:
|
def _on_servers_loaded(self, statusbar: Self, context: "ServerTab") -> None:
|
||||||
count = self.controller.get_player_count()
|
count = self.controller.get_player_count()
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from warnings import deprecated
|
|||||||
from dzgui.views.mixins.context_mixin import ContextMixin
|
from dzgui.views.mixins.context_mixin import ContextMixin
|
||||||
from dzgui.const.enum import ContextMenuGroup, ServerTab
|
from dzgui.const.enum import ContextMenuGroup, ServerTab
|
||||||
from dzgui.api.servers import Record
|
from dzgui.api.servers import Record
|
||||||
|
from dzgui.model.map_model import MapManager
|
||||||
from dzgui.model.filtered_model import FilteredModelManager
|
from dzgui.model.filtered_model import FilteredModelManager
|
||||||
from dzgui.util.dist import CalcDist
|
from dzgui.util.dist import CalcDist
|
||||||
from dzgui.util import strings
|
from dzgui.util import strings
|
||||||
@ -47,6 +48,9 @@ class ServerTreeView(ContextMixin, TreeView):
|
|||||||
model = self.filter_man.get_model()
|
model = self.filter_man.get_model()
|
||||||
self.set_model(model)
|
self.set_model(model)
|
||||||
|
|
||||||
|
# NOTE: each tab context has its own unique maps
|
||||||
|
self.map_man = MapManager()
|
||||||
|
|
||||||
self.set_fixed_height_mode(True)
|
self.set_fixed_height_mode(True)
|
||||||
self.set_headers_visible(True)
|
self.set_headers_visible(True)
|
||||||
|
|
||||||
@ -100,14 +104,26 @@ class ServerTreeView(ContextMixin, TreeView):
|
|||||||
column.connect("notify::fixed-width", self._on_col_width_changed)
|
column.connect("notify::fixed-width", self._on_col_width_changed)
|
||||||
self.append_column(column)
|
self.append_column(column)
|
||||||
|
|
||||||
self.connect("key-press-event", self._on_server_keypress)
|
self.connect("button-press-event", self.present_menu)
|
||||||
self.connect("generic_row_activated", self._parent_row_activated)
|
self.connect("generic_row_activated", self._parent_row_activated)
|
||||||
self.connect("generic_treesel_changed", self._parent_selection_changed)
|
self.connect("generic_treesel_changed", self._parent_selection_changed)
|
||||||
|
self.connect("key-press-event", self._on_server_keypress)
|
||||||
|
self.connect("key-press-event", self.present_menu)
|
||||||
self.connect("map", self._on_map)
|
self.connect("map", self._on_map)
|
||||||
self.connect("unmap", self._on_unmap)
|
self.connect("unmap", self._on_unmap)
|
||||||
|
|
||||||
self.connect("key-press-event", self.present_menu)
|
self.emitter.connect("servers_loaded_init", self._on_servers_loaded_init)
|
||||||
self.connect("button-press-event", self.present_menu)
|
self.emitter.connect("servers_loaded", self._on_servers_loaded)
|
||||||
|
|
||||||
|
def _on_servers_loaded(self, emitter: "Emitter", tab: "ServerTab") -> None:
|
||||||
|
state = self.controller.has_server_model()
|
||||||
|
self.set_headers_clickable(state)
|
||||||
|
|
||||||
|
def _on_servers_loaded_init(self, emitter: "Emitter") -> None:
|
||||||
|
if self.loaded is False:
|
||||||
|
return
|
||||||
|
store = self.map_man.get_map_store()
|
||||||
|
self.emitter.emit("load_maps", store)
|
||||||
|
|
||||||
def _get_ping(
|
def _get_ping(
|
||||||
self,
|
self,
|
||||||
@ -145,6 +161,9 @@ class ServerTreeView(ContextMixin, TreeView):
|
|||||||
def start_timeout(self) -> None:
|
def start_timeout(self) -> None:
|
||||||
self.queue_id = GLib.timeout_add(QUEUE_CHECK_DELAY, self._check_result_queue)
|
self.queue_id = GLib.timeout_add(QUEUE_CHECK_DELAY, self._check_result_queue)
|
||||||
|
|
||||||
|
def get_map_man(self) -> MapManager:
|
||||||
|
return self.map_man
|
||||||
|
|
||||||
def get_filter_man(self) -> FilteredModelManager:
|
def get_filter_man(self) -> FilteredModelManager:
|
||||||
return self.filter_man
|
return self.filter_man
|
||||||
|
|
||||||
@ -174,10 +193,13 @@ class ServerTreeView(ContextMixin, TreeView):
|
|||||||
return self.enum
|
return self.enum
|
||||||
|
|
||||||
def _on_map(self, a) -> None:
|
def _on_map(self, a) -> None:
|
||||||
|
# TODO: disable filter panel if current model is None
|
||||||
if self.get_enum() is ServerTab.LAN:
|
if self.get_enum() is ServerTab.LAN:
|
||||||
self.emitter.emit("lan_tab_toggled", True)
|
self.emitter.emit("lan_tab_toggled", True)
|
||||||
|
|
||||||
# FIXME: only if the tab is active
|
# FIXME: only if the tab is active
|
||||||
|
store = self.map_man.get_map_store()
|
||||||
|
self.emitter.emit("load_maps", store)
|
||||||
self.handler_id = self.emitter.connect("statusbar_loaded", self.start_distcalc)
|
self.handler_id = self.emitter.connect("statusbar_loaded", self.start_distcalc)
|
||||||
self.start_timeout()
|
self.start_timeout()
|
||||||
self.start_distcalc()
|
self.start_distcalc()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user