i implemented the filter and i never want to think about Gtk.TreeIter again

This commit is contained in:
Lynne Megido 2020-09-05 16:51:28 +10:00
parent 4c212c4c21
commit 605c34a9f5
Signed by: lynnesbian
GPG key ID: F0A184B5213D9F90
3 changed files with 355 additions and 83 deletions

View file

@ -47,11 +47,13 @@ namespace Buypeeb {
private Box selectionViewBox;
private Label endingLabel;
private bool queueActive;
private Dictionary<string, CheckButton> filterChecks = new Dictionary<string, CheckButton>();
// ...to here.
static SemaphoreSlim taskLimit = new SemaphoreSlim(6);
private Queue<string> updateQueue = new Queue<string>();
private IEnumerable<YahooAuctionsItem> filterQuery;
private YahooAuctionsItem selectedItem {
get {
@ -106,13 +108,33 @@ namespace Buypeeb {
this.selectionViewBox = (Box)builder.GetObject("SelectionViewBox");
this.endingLabel = (Label)builder.GetObject("LabelSelectedEnding");
foreach (var name in new List<string> { "Favourites", "NonFavourites", "Active", "Ended", "EndingToday", "EndingAfterToday", "WithWinPrice", "WithNoWinPrice" }) {
this.filterChecks.Add(name, (CheckButton)builder.GetObject($"CheckButtonFilter{name}"));
this.filterChecks[name].Active = false;
}
// father forgive me for i have lynned
this.filterQuery =
from item in this.settings.watchlist.Values.ToList()
where (item.favourite != this.filterChecks["Favourites"].Active ||
item.favourite == this.filterChecks["NonFavourites"].Active) &&
(item.available != this.filterChecks["Active"].Active ||
item.available == this.filterChecks["Ended"].Active) &&
(item.endingToday != this.filterChecks["EndingToday"].Active ||
item.endingToday == this.filterChecks["EndingAfterToday"].Active) &&
(item.hasWinPrice != this.filterChecks["WithWinPrice"].Active ||
item.hasWinPrice == this.filterChecks["WithNoWinPrice"].Active)
select item;
Console.WriteLine(this.filterChecks["Favourites"].Active);
// bind treeview columns to watchlist instead of needing to manually sync its liststore
this.itemTreeView = (TreeView)builder.GetObject("TreeViewItems");
this.items = new ListStore(typeof(YahooAuctionsItem));
this.RenderList();
var filteredItems = new TreeModelFilter(this.items, null);
filteredItems.VisibleFunc = this.ItemFilter;
this.itemTreeView.Model = this.items;
this.itemTreeView.Model = filteredItems;
TreeCellDataFunc[] funcs = {
new TreeCellDataFunc(this.RenderColumnFavourite),
new TreeCellDataFunc(this.RenderColumnName),
@ -127,6 +149,7 @@ namespace Buypeeb {
c.SetCellDataFunc(c.Cells[0], funcs[i]);
}
this.RenderList();
this.UpdateItems();
GLib.Timeout.Add(1000, new GLib.TimeoutHandler(UpdateSelectionEndTime));
@ -144,11 +167,13 @@ namespace Buypeeb {
// TODO: surely there's a better way to do this
TreeIter iter;
this.itemTreeView.Model.GetIterFirst(out iter);
var m = (TreeModelFilter)this.itemTreeView.Model;
for (int i = 0; i < this.itemTreeView.Model.IterNChildren(); i++) {
var x = (YahooAuctionsItem)this.itemTreeView.Model.GetValue(iter, 0);
Console.WriteLine(x);
if (x.id == id) {
return (this.itemTreeView.Model.GetPath(iter), iter);
return (m.ConvertPathToChildPath(m.GetPath(iter)), m.ConvertIterToChildIter(iter));
}
else {
this.itemTreeView.Model.IterNext(ref iter);
@ -183,7 +208,9 @@ namespace Buypeeb {
Gtk.Application.Invoke(delegate {
// TODO: find a way to not have to do this. i think we need to avoid actually modifying the items outside of the main thread :/
var pathAndIter = this.GetRow(id);
this.items.EmitRowChanged(pathAndIter.path, pathAndIter.iter);
if (pathAndIter.path != null) {
this.items.EmitRowChanged(pathAndIter.path, pathAndIter.iter);
}
});
using (WebClient client = new WebClient()) {
@ -195,7 +222,9 @@ namespace Buypeeb {
Gtk.Application.Invoke(delegate {
var pathAndIter = this.GetRow(id);
this.items.EmitRowChanged(pathAndIter.path, pathAndIter.iter);
if (pathAndIter.path != null) {
this.items.EmitRowChanged(pathAndIter.path, pathAndIter.iter);
}
if (item == this.selectedItem) {
// if the user has this item selected and it just became ready, enable the selection box
this.selectionViewBox.Sensitive = true;
@ -370,6 +399,8 @@ namespace Buypeeb {
foreach (var item in this.settings.watchlist.Values) {
items.AppendValues(item);
}
var m = (TreeModelFilter)this.itemTreeView.Model;
m.Refilter();
}
// event handlers
@ -598,7 +629,9 @@ namespace Buypeeb {
// i don't know why this is necessary
var pathAndIter = this.GetRow(this.selectedItem.id);
this.items.EmitRowChanged(pathAndIter.path, pathAndIter.iter);
if (pathAndIter.path != null) {
this.items.EmitRowChanged(pathAndIter.path, pathAndIter.iter);
}
}
// timers
@ -681,5 +714,34 @@ namespace Buypeeb {
}
(cell as Gtk.CellRendererText).Text = item.ready ? ending : "...";
}
// tree filter
private bool ItemFilter(ITreeModel model, TreeIter iter) {
var item = (YahooAuctionsItem)model.GetValue(iter, 0);
bool Filtered(string name) {
return this.filterChecks[name].Active;
}
// first, check to see if any filters are set that would exclude everything, such as hiding both active and ended auctions
// if so, there's no need to run the more expensive linq query
if (
(Filtered("Favourites") && Filtered("NonFavourites")) ||
(Filtered("Active") && Filtered("Ended")) ||
(Filtered("EndingToday") && Filtered("EndingAfterToday")) ||
(Filtered("WithWinPrice") && Filtered("WithNoWinPrice"))
) {
return false;
}
// this.filterQuery.ToList().ForEach(Console.WriteLine);
return this.filterQuery.Contains(item);
}
private void RunFilter(object sender, EventArgs a) {
var m = (TreeModelFilter)this.itemTreeView.Model;
m.Refilter();
}
}
}

View file

@ -45,32 +45,13 @@ namespace Buypeeb {
}
}
public string priceJPY {
get {
return $"¥{this.price}";
}
}
public string winPriceJPY {
get {
return $"¥{this.winPrice}";
}
}
public string priceAUD {
get {
double aud = this.price / 75.0;
return $"${aud:f2}";
}
}
public string winPriceAUD {
get {
double aud = this.winPrice / 75.0;
return $"${aud:f2}";
}
}
// TODO: don't serialise this stuff
public string priceJPY { get { return $"¥{this.price}"; } }
public string winPriceJPY { get { return $"¥{this.winPrice}"; } }
public string priceAUD { get { return $"${(this.price / 75.0):f2}"; } }
public string winPriceAUD { get { return $"${(this.winPrice / 75.0):f2}"; } }
public bool endingToday { get { return this.endDate.DayOfYear == DateTime.UtcNow.DayOfYear; } }
public bool hasWinPrice { get { return this.winPrice != 0; } }
private bool success { get; set; } // TODO: custom setter that throws an exception if set to false or something idk
public YahooAuctionsItem(string id, string name) {
@ -129,5 +110,9 @@ namespace Buypeeb {
this.autoExtension = (m.Groups[1].Value == "あり");
}
}
public override string ToString() {
return $"{this.id}: {this.name}";
}
}
}

View file

@ -3,6 +3,171 @@
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkTextBuffer" id="TextBufferSelectedNotes"/>
<object class="GtkPopover" id="popover1">
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_start">5</property>
<property name="margin_end">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="orientation">vertical</property>
<property name="spacing">3</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="label" translatable="yes">Items to hide:</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="CheckButtonFilterFavourites">
<property name="label" translatable="yes">Favourites</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="RunFilter" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="CheckButtonFilterNonFavourites">
<property name="label" translatable="yes">Non-favourites</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="RunFilter" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="CheckButtonFilterActive">
<property name="label" translatable="yes">Active</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="RunFilter" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="CheckButtonFilterEnded">
<property name="label" translatable="yes">Ended</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="RunFilter" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="CheckButtonFilterEndingToday">
<property name="label" translatable="yes">Ending today</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="RunFilter" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="CheckButtonFilterEndingAfterToday">
<property name="label" translatable="yes">Ending after today</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="RunFilter" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="CheckButtonFilterWithWinPrice">
<property name="label" translatable="yes">With win price</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="RunFilter" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="CheckButtonFilterWithNoWinPrice">
<property name="label" translatable="yes">With no win price</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="RunFilter" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Show all</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">9</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkWindow" id="wndMain">
<property name="can_focus">False</property>
<property name="default_width">810</property>
@ -279,75 +444,135 @@
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="shadow_type">in</property>
<property name="min_content_width">200</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkTreeView" id="TreeViewItems">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_start">3</property>
<property name="margin_end">3</property>
<property name="spacing">3</property>
<child>
<object class="GtkSearchEntry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">True</property>
<property name="popover">popover1</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="rules_hint">True</property>
<property name="search_column">1</property>
<property name="activate_on_single_click">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection">
<signal name="changed" handler="TreeViewItemsSelectionChanged" swapped="no"/>
</object>
</child>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="shadow_type">in</property>
<property name="min_content_width">200</property>
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">♥</property>
<child>
<object class="GtkCellRendererText"/>
<object class="GtkTreeView" id="TreeViewItems">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="rules_hint">True</property>
<property name="enable_search">False</property>
<property name="search_column">1</property>
<property name="activate_on_single_click">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection">
<signal name="changed" handler="TreeViewItemsSelectionChanged" swapped="no"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="sizing">fixed</property>
<property name="fixed_width">100</property>
<property name="title" translatable="yes">Name</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<child>
<object class="GtkCellRendererText"/>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">♥</property>
<child>
<object class="GtkCellRendererText"/>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="title" translatable="yes">Price (¥)</property>
<child>
<object class="GtkCellRendererText"/>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="sizing">fixed</property>
<property name="fixed_width">100</property>
<property name="title" translatable="yes">Name</property>
<property name="expand">True</property>
<property name="clickable">True</property>
<child>
<object class="GtkCellRendererText"/>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="title" translatable="yes">Price (AUD)</property>
<child>
<object class="GtkCellRendererText"/>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="title" translatable="yes">Price (¥)</property>
<child>
<object class="GtkCellRendererText"/>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="title" translatable="yes">Ending at</property>
<property name="clickable">True</property>
<child>
<object class="GtkCellRendererText"/>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="title" translatable="yes">Price (AUD)</property>
<child>
<object class="GtkCellRendererText"/>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="title" translatable="yes">Ending at</property>
<property name="clickable">True</property>
<child>
<object class="GtkCellRendererText"/>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>