Favorites and fixes.

Favorites functionality done, except editing favorite server.
Note, that game profile defined for favorite server have
higher priority on normal profile selected in combobox near
"Launch!" button. Later WILL be ignored.

Bunch of fixes is added.
This commit is contained in:
Stanislav Nikitin 2016-10-04 23:39:32 +05:00
parent d6765501a8
commit 063f6a622a
7 changed files with 608 additions and 54 deletions

View File

@ -16,11 +16,14 @@ updating information about them.
* Extended Urban Terror launching capabilities (e.g. launching game
in another X session).
* Supporting of multiple profiles with multiple game versions.
When you're launching Urban Terror URTrator will check profile you're
trying to use and, if version incompatability found, will not launch
the game.
* Favorites servers.
Planning:
* Updating single server.
* Favorites servers.
* Showing information about servers (like in UrT Connector).
* Friends searching.
* RCON console.

View File

@ -65,12 +65,48 @@ func (d *Database) Migrate() {
func (d *Database) UpdateServers(data map[string]*datamodels.Server) {
fmt.Println("Updating servers information in database...")
// ToDo: real update :)
d.Db.MustExec("DELETE FROM servers")
raw_cached := []datamodels.Server{}
d.Db.Select(&raw_cached, "SELECT * FROM servers")
// Create map[string]*datamodels.Server once, so we won't iterate
// over slice of datamodels.Server everytime.
cached_servers := make(map[string]*datamodels.Server)
for s := range raw_cached {
mapping_item_name := raw_cached[s].Ip + ":" + raw_cached[s].Port
cached_servers[mapping_item_name] = &raw_cached[s]
}
new_servers := make(map[string]*datamodels.Server)
// Update our cached mapping.
for _, s := range data {
mapping_item_name := s.Ip + ":" + s.Port
_, ok := cached_servers[mapping_item_name]
if !ok {
fmt.Println(mapping_item_name + " not found!")
new_servers[mapping_item_name] = s
} else {
cached_servers[mapping_item_name].Ip = s.Ip
cached_servers[mapping_item_name].Port = s.Port
cached_servers[mapping_item_name].Name = s.Name
cached_servers[mapping_item_name].Players = s.Players
cached_servers[mapping_item_name].Maxplayers = s.Maxplayers
cached_servers[mapping_item_name].Ping = s.Ping
cached_servers[mapping_item_name].Map = s.Map
cached_servers[mapping_item_name].Gamemode = s.Gamemode
}
}
tx := d.Db.MustBegin()
for _, srv := range data {
fmt.Println("Adding new servers...")
for _, srv := range new_servers {
tx.NamedExec("INSERT INTO servers (ip, port, name, ping, players, maxplayers, gamemode, map, version) VALUES (:ip, :port, :name, :ping, :players, :maxplayers, :gamemode, :map, :version)", srv)
}
fmt.Println("Updating cached servers...")
for _, srv := range cached_servers {
tx.NamedExec("UPDATE servers SET name=:name, players=:players, maxplayers=:maxplayers, gamemode=:gamemode, map=:map, version=:version WHERE ip=:ip AND port=:port", &srv)
}
tx.Commit()
fmt.Println("Done")
}

View File

@ -55,6 +55,14 @@ func migrate_full(db *Database, version int) {
three_to_four(db)
version = 4
}
if version == 4 {
four_to_five(db)
version = 5
}
if version == 5 {
five_to_six(db)
version = 6
}
}
// Initial database structure.
@ -84,4 +92,19 @@ func two_to_three(db *Database) {
func three_to_four(db *Database) {
fmt.Println("Upgrading database from 3 to 4...")
db.Db.MustExec("UPDATE urt_profiles SET version='4.3.0' WHERE version='4.3.000'")
db.Db.MustExec("UPDATE database SET version=4")
}
// Server's passwords.
func four_to_five(db *Database) {
fmt.Println("Upgrading database from 4 to 5...")
db.Db.MustExec("ALTER TABLE servers ADD password VARCHAR(64) DEFAULT ''")
db.Db.MustExec("UPDATE database SET version=5")
}
// Profile for server.
func five_to_six(db *Database) {
fmt.Println("Upgrading database from 5 to 6...")
db.Db.MustExec("ALTER TABLE servers ADD profile_to_use VARCHAR(128) DEFAULT ''")
db.Db.MustExec("UPDATE database SET version=6")
}

View File

@ -30,4 +30,8 @@ type Server struct {
Version string `db:"version"`
// Is server was favorited?
Favorite string `db:"favorite"`
// Server's password.
Password string `db:"password"`
// Profile to use with server.
ProfileToUse string `db:"profile_to_use"`
}

View File

@ -144,6 +144,12 @@ func (r *Requester) UpdateAllServers(done_chan chan map[string]*datamodels.Serve
done_chan <- servers
}
func (r *Requester) UpdateFavoriteServers(servers [][]string, done_chan chan map[string]*datamodels.Server, error_chan chan bool) {
fmt.Println("Updating favorites servers...")
updated_servers := r.updateServerGoroutineDispatcher(servers)
done_chan <- updated_servers
}
func (r *Requester) updateServerGoroutineDispatcher(data [][]string) map[string]*datamodels.Server {
var wait sync.WaitGroup
var lock = sync.RWMutex{}

223
ui/favorite.go Normal file
View File

@ -0,0 +1,223 @@
// URTator - Urban Terror server browser and game launcher, written in
// Go.
//
// Copyright (c) 2016, Stanslav N. a.k.a pztrn (or p0z1tr0n)
// All rights reserved.
//
// Licensed under Terms and Conditions of GNU General Public License
// version 3 or any higher.
// ToDo: put full text of license here.
package ui
import (
// stdlib
"encoding/base64"
"errors"
"fmt"
"strings"
// Local
"github.com/pztrn/urtrator/common"
"github.com/pztrn/urtrator/datamodels"
// Other
"github.com/mattn/go-gtk/gdkpixbuf"
"github.com/mattn/go-gtk/gtk"
)
type FavoriteDialog struct {
// Widgets.
// Dialog's window.
window *gtk.Window
// Main vertical box.
vbox *gtk.VBox
// Server name.
server_name *gtk.Entry
// Server address.
server_address *gtk.Entry
// Server password
server_password *gtk.Entry
// Profile.
profile *gtk.ComboBoxText
// Flags.
// Is known server update performed?
update bool
// Data.
// If known server is used - here server's datamodel is.
server *datamodels.Server
}
func (f *FavoriteDialog) Close() {}
func (f *FavoriteDialog) closeByCancel() {
f.window.Destroy()
}
func (f *FavoriteDialog) fill() {
f.server_name.SetText(f.server.Name)
f.server_address.SetText(f.server.Ip + ":" + f.server.Port)
f.server_password.SetText(f.server.Password)
// Profiles.
profiles := []datamodels.Profile{}
err := ctx.Database.Db.Select(&profiles, "SELECT * FROM urt_profiles")
if err != nil {
fmt.Println(err.Error())
}
for p := range profiles {
if profiles[p].Version == f.server.Version {
f.profile.AppendText(profiles[p].Name)
}
}
}
func (f *FavoriteDialog) Initialize() {
if f.update {
fmt.Println("Updating favorite server...")
} else {
fmt.Println("New favorite server")
}
f.initializeWindow()
}
func (f *FavoriteDialog) InitializeNew() {
f.update = false
f.Initialize()
}
func (f *FavoriteDialog) InitializeUpdate(server *datamodels.Server) {
fmt.Println("Favorites updating...")
f.update = true
f.server = server
f.Initialize()
f.fill()
}
func (f *FavoriteDialog) initializeWindow() {
f.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
if f.update {
f.window.SetTitle("URTrator - Updating favorite server")
} else {
f.window.SetTitle("URTrator - New favorite server")
}
f.window.Connect("destroy", f.Close)
f.window.SetPosition(gtk.WIN_POS_CENTER)
f.window.SetModal(true)
f.window.SetSizeRequest(400, 200)
f.window.SetResizable(false)
f.vbox = gtk.NewVBox(false, 0)
// Load program icon from base64.
icon_bytes, _ := base64.StdEncoding.DecodeString(common.Logo)
icon_pixbuf := gdkpixbuf.NewLoader()
icon_pixbuf.Write(icon_bytes)
logo = icon_pixbuf.GetPixbuf()
f.window.SetIcon(logo)
// Server name.
srv_name_hbox := gtk.NewHBox(false, 0)
f.vbox.PackStart(srv_name_hbox, false, true, 5)
srv_name_label := gtk.NewLabel("Server name:")
srv_name_hbox.PackStart(srv_name_label, false, true, 5)
srv_name_sep := gtk.NewHSeparator()
srv_name_hbox.PackStart(srv_name_sep, true, true, 5)
f.server_name = gtk.NewEntry()
srv_name_hbox.PackStart(f.server_name, true, true, 5)
// Server address.
srv_addr_hbox := gtk.NewHBox(false, 0)
f.vbox.PackStart(srv_addr_hbox, false, true, 5)
srv_addr_label := gtk.NewLabel("Server address:")
srv_addr_hbox.PackStart(srv_addr_label, false, true, 5)
srv_addr_sep := gtk.NewHSeparator()
srv_addr_hbox.PackStart(srv_addr_sep, true, true, 5)
f.server_address = gtk.NewEntry()
srv_addr_hbox.PackStart(f.server_address, true, true, 5)
if f.update {
f.server_address.SetSensitive(false)
}
// Server password.
srv_pass_hbox := gtk.NewHBox(false, 0)
f.vbox.PackStart(srv_pass_hbox, false, true, 5)
srv_pass_label := gtk.NewLabel("Password:")
srv_pass_hbox.PackStart(srv_pass_label, false, true, 5)
srv_pass_sep := gtk.NewHSeparator()
srv_pass_hbox.PackStart(srv_pass_sep, true, true, 5)
f.server_password = gtk.NewEntry()
srv_pass_hbox.PackStart(f.server_password, true, true, 5)
// Profile to use.
profile_hbox := gtk.NewHBox(false, 0)
f.vbox.PackStart(profile_hbox, false, true, 5)
profile_label := gtk.NewLabel("Profile:")
profile_hbox.PackStart(profile_label, false, true, 5)
profile_sep := gtk.NewHSeparator()
profile_hbox.PackStart(profile_sep, true, true, 5)
f.profile = gtk.NewComboBoxText()
profile_hbox.PackStart(f.profile, false, true, 5)
// Buttons hbox.
buttons_hbox := gtk.NewHBox(false, 0)
sep := gtk.NewHSeparator()
buttons_hbox.PackStart(sep, true, true, 5)
// OK-Cancel buttons.
cancel_button := gtk.NewButtonWithLabel("Cancel")
cancel_button.Clicked(f.closeByCancel)
buttons_hbox.PackStart(cancel_button, false, true, 5)
ok_button := gtk.NewButtonWithLabel("OK")
ok_button.Clicked(f.saveFavorite)
buttons_hbox.PackStart(ok_button, false, true, 5)
f.vbox.PackStart(buttons_hbox, false, true, 5)
f.window.Add(f.vbox)
f.window.ShowAll()
}
func (f *FavoriteDialog) saveFavorite() error {
if len(f.server_address.GetText()) == 0 {
mbox_string := "Server address is empty.\n\nServers without address cannot be added."
m := gtk.NewMessageDialog(f.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() {
m.Destroy()
})
m.Run()
return errors.New("No server address specified")
}
var port string = ""
if strings.Contains(f.server_address.GetText(), ":") {
port = strings.Split(f.server_address.GetText(), ":")[1]
} else {
port = "27960"
}
fmt.Println("Saving favorite server...")
server := datamodels.Server{}
server.Ip = strings.Split(f.server_address.GetText(), ":")[0]
server.Port = port
server.Name = f.server_name.GetText()
server.Password = f.server_password.GetText()
server.ProfileToUse = f.profile.GetActiveText()
server.Favorite = "1"
if f.update {
q := "UPDATE servers SET name=:name, ip=:ip, port=:port, password=:password, favorite=:favorite, profile_to_use=:profile_to_use WHERE ip='" + f.server.Ip + "' AND port='" + f.server.Port + "'"
fmt.Println("Query: " + q)
ctx.Database.Db.NamedExec(q, &server)
} else {
q := "INSERT INTO servers (name, ip, port, password, favorite, profile_to_use) VALUES (:name, :ip, :port, :password, \"1\", :profile_to_use)"
fmt.Println(q)
ctx.Database.Db.NamedExec(q, &server)
}
ctx.Eventer.LaunchEvent("loadFavoriteServers")
return nil
}

View File

@ -15,6 +15,7 @@ import (
"errors"
"fmt"
"strconv"
"strings"
// Local
"github.com/pztrn/urtrator/common"
@ -61,6 +62,10 @@ type MainWindow struct {
fav_servers_hide_offline *gtk.CheckButton
// Game launch button.
launch_button *gtk.Button
// Quick connect: server address
qc_server_address *gtk.Entry
// Quick connect: password
qc_password *gtk.Entry
// Storages.
// All servers store.
@ -72,6 +77,8 @@ type MainWindow struct {
// Dialogs.
options_dialog *OptionsDialog
// Favorite server editing.
favorite_dialog *FavoriteDialog
// Other
// Old profiles count.
@ -80,12 +87,125 @@ type MainWindow struct {
func (m *MainWindow) addToFavorites() {
fmt.Println("Adding server to favorites...")
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
// Getting server's address from list.
sel := m.all_servers.GetSelection()
model := m.all_servers.GetModel()
if strings.Contains(current_tab, "Favorites") {
// Getting server's address from list.
sel = m.fav_servers.GetSelection()
model = m.fav_servers.GetModel()
}
iter := new(gtk.TreeIter)
_ = sel.GetSelected(iter)
// Getting server address.
var srv_addr string
srv_addr_gval := glib.ValueFromNative(srv_addr)
model.GetValue(iter, 7, srv_addr_gval)
server_address := srv_addr_gval.GetString()
// Getting server from database.
m.favorite_dialog = &FavoriteDialog{}
if len(server_address) > 0 {
servers := []datamodels.Server{}
address := strings.Split(server_address, ":")[0]
port := strings.Split(server_address, ":")[1]
err1 := ctx.Database.Db.Select(&servers, ctx.Database.Db.Rebind("SELECT * FROM servers WHERE ip=? AND port=?"), address, port)
if err1 != nil {
fmt.Println(err1.Error())
}
m.favorite_dialog.InitializeUpdate(&servers[0])
} else {
m.favorite_dialog.InitializeNew()
}
}
func (m *MainWindow) Close() {
ctx.Close()
}
func (m *MainWindow) deleteFromFavorites() {
fmt.Println("Removing server from favorites...")
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
// Assuming that deletion was called from "Servers" tab by default.
sel := m.all_servers.GetSelection()
model := m.all_servers.GetModel()
if strings.Contains(current_tab, "Favorites") {
// Getting server's address from list.
sel = m.fav_servers.GetSelection()
model = m.fav_servers.GetModel()
}
iter := new(gtk.TreeIter)
_ = sel.GetSelected(iter)
// Getting server address.
var srv_addr string
srv_addr_gval := glib.ValueFromNative(srv_addr)
model.GetValue(iter, 7, srv_addr_gval)
server_address := srv_addr_gval.GetString()
var not_favorited bool = false
if len(server_address) > 0 {
address := strings.Split(server_address, ":")[0]
port := strings.Split(server_address, ":")[1]
srv := []datamodels.Server{}
err := ctx.Database.Db.Select(&srv, ctx.Database.Db.Rebind("SELECT * FROM servers WHERE ip=? AND port=?"), address, port)
if err != nil {
fmt.Println(err.Error())
}
if srv[0].Favorite == "1" {
ctx.Database.Db.MustExec(ctx.Database.Db.Rebind("UPDATE servers SET favorite='0' WHERE ip=? AND port=?"), address, port)
ctx.Eventer.LaunchEvent("loadFavoriteServers")
} else {
not_favorited = true
}
} else {
not_favorited = true
}
if not_favorited {
mbox_string := "Cannot delete server from favorites.\n\nServer isn't favorited."
d := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, mbox_string)
d.Response(func() {
d.Destroy()
})
d.Run()
}
}
func (m *MainWindow) dropDatabasesData() {
fmt.Println("Dropping database data...")
var will_continue bool = false
mbox_string := "You are about to drop whole database data.\n\nAfter clicking \"YES\" ALL data in database (servers, profiles, settings, etc.)\nwill be lost FOREVER. Are you sure?"
d := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, mbox_string)
d.Connect("response", func(resp *glib.CallbackContext) {
if resp.Args(0) == 4294967287 {
will_continue = false
} else {
will_continue = true
}
})
d.Response(func() {
d.Destroy()
})
d.Run()
if will_continue {
ctx.Database.Db.MustExec("DELETE FROM servers")
ctx.Database.Db.MustExec("DELETE FROM settings")
ctx.Database.Db.MustExec("DELETE FROM urt_profiles")
ctx.Eventer.LaunchEvent("loadProfiles")
ctx.Eventer.LaunchEvent("loadAllServers")
ctx.Eventer.LaunchEvent("loadFavoriteServers")
}
}
func (m *MainWindow) hideOfflineAllServers() {
fmt.Println("(Un)Hiding offline servers in 'Servers' tab...")
ctx.Eventer.LaunchEvent("loadAllServers")
@ -93,6 +213,7 @@ func (m *MainWindow) hideOfflineAllServers() {
func (m *MainWindow) hideOfflineFavoriteServers() {
fmt.Println("(Un)Hiding offline servers in 'Favorite' tab...")
ctx.Eventer.LaunchEvent("loadFavoriteServers")
}
func (m *MainWindow) Initialize() {
@ -137,7 +258,7 @@ func (m *MainWindow) Initialize() {
// Temporary hack.
var w, h int = 0, 0
m.window.GetSize(&w, &h)
m.hpane.SetPosition(w)
m.hpane.SetPosition(w - 150)
// Game profiles and launch button.
profile_and_launch_hbox := gtk.NewHBox(false, 0)
@ -180,6 +301,7 @@ func (m *MainWindow) Initialize() {
// Launch events.
ctx.Eventer.LaunchEvent("loadProfiles")
ctx.Eventer.LaunchEvent("loadAllServers")
ctx.Eventer.LaunchEvent("loadFavoriteServers")
gtk.Main()
}
@ -199,6 +321,10 @@ func (m *MainWindow) InitializeMainMenu() {
file_menu.Append(options_menu_item)
options_menu_item.Connect("activate", m.options_dialog.ShowOptionsDialog)
// Separator.
file_menu_sep1 := gtk.NewSeparatorMenuItem()
file_menu.Append(file_menu_sep1)
// Exit.
exit_menu_item := gtk.NewMenuItemWithMnemonic("E_xit")
file_menu.Append(exit_menu_item)
@ -214,11 +340,46 @@ func (m *MainWindow) InitializeMainMenu() {
about_app_item := gtk.NewMenuItemWithMnemonic("About _URTrator...")
about_menu.Append(about_app_item)
about_app_item.Connect("activate", ShowAboutDialog)
// Separator.
about_menu_sep1 := gtk.NewSeparatorMenuItem()
about_menu.Append(about_menu_sep1)
// Drop databases thing.
about_menu_drop_database_data_item := gtk.NewMenuItemWithMnemonic("Drop database data...")
about_menu.Append(about_menu_drop_database_data_item)
about_menu_drop_database_data_item.Connect("activate", m.dropDatabasesData)
}
func (m *MainWindow) initializeSidebar() {
sidebar_vbox := gtk.NewVBox(false, 0)
// Quick connect frame.
quick_connect_frame := gtk.NewFrame("Quick connect")
sidebar_vbox.PackStart(quick_connect_frame, true, true, 5)
qc_vbox := gtk.NewVBox(false, 0)
quick_connect_frame.Add(qc_vbox)
// Server address.
srv_tooltip := "Server address we will connect to"
srv_label := gtk.NewLabel("Server address:")
srv_label.SetTooltipText(srv_tooltip)
qc_vbox.PackStart(srv_label, false, true, 5)
m.qc_server_address = gtk.NewEntry()
m.qc_server_address.SetTooltipText(srv_tooltip)
qc_vbox.PackStart(m.qc_server_address, false, true, 5)
// Password.
pass_tooltip := "Password we will use for server"
pass_label := gtk.NewLabel("Password:")
pass_label.SetTooltipText(pass_tooltip)
qc_vbox.PackStart(pass_label, false, true, 5)
m.qc_password = gtk.NewEntry()
m.qc_password.SetTooltipText(pass_tooltip)
qc_vbox.PackStart(m.qc_password, false, true, 5)
m.hpane.Add2(sidebar_vbox)
}
@ -331,13 +492,34 @@ func (m *MainWindow) InitializeTabs() {
m.tab_widget.AppendPage(tab_fav_srv_hbox, gtk.NewLabel("Favorites"))
m.fav_servers.SetModel(m.fav_servers_store)
m.fav_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Status", gtk.NewCellRendererPixbuf(), "pixbuf", 0))
m.fav_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Name", gtk.NewCellRendererText(), "text", 1))
m.fav_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Mode", gtk.NewCellRendererText(), "text", 2))
m.fav_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Map", gtk.NewCellRendererText(), "text", 3))
m.fav_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Players", gtk.NewCellRendererText(), "text", 4))
m.fav_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Ping", gtk.NewCellRendererText(), "text", 5))
m.fav_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("Version", gtk.NewCellRendererText(), "text", 6))
m.fav_servers.AppendColumn(gtk.NewTreeViewColumnWithAttributes("IP", gtk.NewCellRendererText(), "text", 7))
fav_name_column := gtk.NewTreeViewColumnWithAttributes("Name", gtk.NewCellRendererText(), "text", 1)
fav_name_column.SetSortColumnId(1)
m.fav_servers.AppendColumn(fav_name_column)
fav_mode_column := gtk.NewTreeViewColumnWithAttributes("Mode", gtk.NewCellRendererText(), "text", 2)
fav_mode_column.SetSortColumnId(2)
m.fav_servers.AppendColumn(fav_mode_column)
fav_map_column := gtk.NewTreeViewColumnWithAttributes("Map", gtk.NewCellRendererText(), "text", 3)
fav_map_column.SetSortColumnId(3)
m.fav_servers.AppendColumn(fav_map_column)
fav_players_column := gtk.NewTreeViewColumnWithAttributes("Players", gtk.NewCellRendererText(), "text", 4)
fav_players_column.SetSortColumnId(4)
m.fav_servers.AppendColumn(fav_players_column)
fav_ping_column := gtk.NewTreeViewColumnWithAttributes("Ping", gtk.NewCellRendererText(), "text", 5)
fav_ping_column.SetSortColumnId(5)
m.fav_servers.AppendColumn(fav_ping_column)
fav_version_column := gtk.NewTreeViewColumnWithAttributes("Version", gtk.NewCellRendererText(), "text", 6)
fav_version_column.SetSortColumnId(6)
m.fav_servers.AppendColumn(fav_version_column)
fav_ip_column := gtk.NewTreeViewColumnWithAttributes("IP", gtk.NewCellRendererText(), "text", 7)
fav_ip_column.SetSortColumnId(7)
m.fav_servers.AppendColumn(fav_ip_column)
// VBox for some servers list controllers.
tab_fav_srv_ctl_vbox := gtk.NewVBox(false, 0)
@ -356,7 +538,8 @@ func (m *MainWindow) InitializeTabs() {
// Add tab_widget widget to window.
m.hpane.Add1(m.tab_widget)
ctx.Eventer.AddEventHandler("loadAllServers", m.loadServers)
ctx.Eventer.AddEventHandler("loadAllServers", m.loadAllServers)
ctx.Eventer.AddEventHandler("loadFavoriteServers", m.loadFavoriteServers)
}
func (m *MainWindow) InitializeToolbar() {
@ -380,17 +563,26 @@ func (m *MainWindow) InitializeToolbar() {
fav_button.SetTooltipText("Add selected server to favorites")
fav_button.OnClicked(m.addToFavorites)
m.toolbar.Insert(fav_button, 2)
// Remove server from favorites button.
fav_delete_button := gtk.NewToolButtonFromStock(gtk.STOCK_REMOVE)
fav_delete_button.SetLabel("Remove from favorites")
fav_delete_button.SetTooltipText("Remove selected server from favorites")
fav_delete_button.OnClicked(m.deleteFromFavorites)
m.toolbar.Insert(fav_delete_button, 3)
}
func (m *MainWindow) launchGame() error {
fmt.Println("Launching Urban Terror...")
//var launch_params string = ""
// Getting server's name from list.
// ToDo: detect on what tab we are and use approriate list.
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
sel := m.all_servers.GetSelection()
model := m.all_servers.GetModel()
if strings.Contains(current_tab, "Favorites") {
sel = m.fav_servers.GetSelection()
model = m.fav_servers.GetModel()
}
iter := new(gtk.TreeIter)
_ = sel.GetSelected(iter)
@ -412,7 +604,6 @@ func (m *MainWindow) launchGame() error {
model.GetValue(iter, 6, srv_game_ver_gval)
srv_game_ver := srv_game_ver_gval.GetString()
// Check for proper server name. If length == 0: server is offline,
// we should show notification to user.
if len(server_name) == 0 {
@ -437,19 +628,33 @@ func (m *MainWindow) launchGame() error {
// Getting selected profile's name.
profile_name := m.profiles.GetActiveText()
// Checking profile name length. If 0 - then stop executing :)
if len(profile_name) == 0 {
mbox_string := "Invalid game profile selected.\n\nPlease, select profile and retry."
m := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() {
m.Destroy()
})
m.Run()
return errors.New("User didn't select valid profile.")
if strings.Contains(current_tab, "Servers") {
// Checking profile name length. If 0 - then stop executing :)
// This check only relevant to "Servers" tab, favorite servers
// have profiles defined (see next).
if len(profile_name) == 0 {
mbox_string := "Invalid game profile selected.\n\nPlease, select profile and retry."
m := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() {
m.Destroy()
})
m.Run()
return errors.New("User didn't select valid profile.")
}
} else if strings.Contains(current_tab, "Favorites") {
// For favorite servers profile specified in favorite server
// information have higher priority, so we just override it :)
server := []datamodels.Server{}
// All favorites servers should contain IP and Port :)
ip := strings.Split(srv_address, ":")[0]
port := strings.Split(srv_address, ":")[1]
err := ctx.Database.Db.Select(&server, ctx.Database.Db.Rebind("SELECT * FROM servers WHERE ip=? AND port=?"), ip, port)
if err != nil {
fmt.Println(err.Error())
}
profile_name = server[0].ProfileToUse
}
fmt.Println("Connecting to " + server_name + " (" + srv_address + ") using profile " + profile_name + "...")
// Getting profile data from database.
// ToDo: cache profiles data in runtime.
profile := []datamodels.Profile{}
@ -478,28 +683,7 @@ func (m *MainWindow) launchGame() error {
return nil
}
func (m *MainWindow) loadProfiles() {
fmt.Println("Loading profiles into combobox on MainWindow")
for i := 0; i < m.old_profiles_count; i++ {
// ComboBox indexes are shifting on element deletion, so we should
// detele very first element every time.
m.profiles.Remove(0)
}
profiles := []datamodels.Profile{}
err := ctx.Database.Db.Select(&profiles, "SELECT * FROM urt_profiles")
if err != nil {
fmt.Println(err.Error())
}
for p := range profiles {
m.profiles.AppendText(profiles[p].Name)
}
m.old_profiles_count = len(profiles)
fmt.Println("Added " + strconv.Itoa(m.old_profiles_count) + " profiles")
}
func (m *MainWindow) loadServers() {
func (m *MainWindow) loadAllServers() {
fmt.Println("Loading servers lists into widgets...")
servers := []datamodels.Server{}
err := ctx.Database.Db.Select(&servers, "SELECT * FROM servers")
@ -529,28 +713,103 @@ func (m *MainWindow) loadServers() {
}
}
func (m *MainWindow) loadFavoriteServers() {
fmt.Println("Loading favorite servers...")
servers := []datamodels.Server{}
err := ctx.Database.Db.Select(&servers, "SELECT * FROM servers WHERE favorite='1'")
if err != nil {
fmt.Println(err.Error())
}
// ToDo: do it without clearing.
m.fav_servers_store.Clear()
for _, srv := range servers {
if srv.Favorite != "1" {
continue
}
if m.fav_servers_hide_offline.GetActive() && srv.Name == "" && srv.Players == "" {
continue
}
var iter gtk.TreeIter
m.fav_servers_store.Append(&iter)
if srv.Name == "" && srv.Players == "" {
m.fav_servers_store.Set(&iter, 0, gtk.NewImage().RenderIcon(gtk.STOCK_NO, gtk.ICON_SIZE_SMALL_TOOLBAR, "").GPixbuf)
} else {
m.fav_servers_store.Set(&iter, 0, gtk.NewImage().RenderIcon(gtk.STOCK_OK, gtk.ICON_SIZE_SMALL_TOOLBAR, "").GPixbuf)
}
m.fav_servers_store.Set(&iter, 1, srv.Name)
m.fav_servers_store.Set(&iter, 2, m.gamemodes[srv.Gamemode])
m.fav_servers_store.Set(&iter, 3, srv.Map)
m.fav_servers_store.Set(&iter, 4, srv.Players + "/" + srv.Maxplayers)
m.fav_servers_store.Set(&iter, 5, srv.Ping)
m.fav_servers_store.Set(&iter, 6, srv.Version)
m.fav_servers_store.Set(&iter, 7, srv.Ip + ":" + srv.Port)
}
}
func (m *MainWindow) loadProfiles() {
fmt.Println("Loading profiles into combobox on MainWindow")
for i := 0; i < m.old_profiles_count; i++ {
// ComboBox indexes are shifting on element deletion, so we should
// detele very first element every time.
m.profiles.Remove(0)
}
profiles := []datamodels.Profile{}
err := ctx.Database.Db.Select(&profiles, "SELECT * FROM urt_profiles")
if err != nil {
fmt.Println(err.Error())
}
for p := range profiles {
m.profiles.AppendText(profiles[p].Name)
}
m.old_profiles_count = len(profiles)
fmt.Println("Added " + strconv.Itoa(m.old_profiles_count) + " profiles")
}
func (m *MainWindow) unlockInterface() {
m.launch_button.SetSensitive(true)
m.statusbar.Push(m.statusbar_context_id, "URTrator is ready.")
}
func (m *MainWindow) updateFavorites(done_chan chan map[string]*datamodels.Server, error_chan chan bool) {
m.fav_servers_store.Clear()
servers := []datamodels.Server{}
err := ctx.Database.Db.Select(&servers, "SELECT * FROM servers WHERE favorite='1'")
if err != nil {
fmt.Println(err.Error())
}
var servers_from_db [][]string
for s := range servers {
servers_from_db = append(servers_from_db, []string{servers[s].Ip, servers[s].Port})
}
go ctx.Requester.UpdateFavoriteServers(servers_from_db, done_chan, error_chan)
}
func (m *MainWindow) UpdateServers() {
m.statusbar.Push(m.statusbar_context_id, "Updating servers...")
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
fmt.Println("Updating servers on tab '" + current_tab + "'...")
done_chan := make(chan map[string]*datamodels.Server, 1)
error_chan := make(chan bool, 1)
if current_tab == "Servers" {
if strings.Contains(current_tab, "Servers") {
go ctx.Requester.UpdateAllServers(done_chan, error_chan)
} else if current_tab == "Favorites" {
fmt.Println("Favorites update stub")
} else if strings.Contains(current_tab, "Favorites") {
m.updateFavorites(done_chan, error_chan)
}
select {
case data := <- done_chan:
fmt.Println("Information about servers successfully gathered")
ctx.Database.UpdateServers(data)
ctx.Eventer.LaunchEvent("loadAllServers")
if current_tab == "Servers" {
ctx.Eventer.LaunchEvent("loadAllServers")
} else {
ctx.Eventer.LaunchEvent("loadFavoriteServers")
}
case <- error_chan:
fmt.Println("Error occured")
}