Updated to latest GTK2 bindings API and moved to Gitlab.

This commit is contained in:
Stanislav Nikitin 2018-11-10 13:21:53 +05:00
parent 070aa50762
commit 127e1b8ab9
27 changed files with 3347 additions and 3351 deletions

50
cache/cache_object.go vendored
View File

@ -10,41 +10,41 @@
package cache package cache
import ( import (
// stdlib // stdlib
"fmt" "fmt"
"sync" "sync"
// local // local
"github.com/pztrn/urtrator/cachemodels" "gitlab.com/pztrn/urtrator/cachemodels"
) )
type Cache struct { type Cache struct {
// Profiles cache. // Profiles cache.
Profiles map[string]*cachemodels.Profile Profiles map[string]*cachemodels.Profile
// Profiles cache mutex. // Profiles cache mutex.
ProfilesMutex sync.Mutex ProfilesMutex sync.Mutex
// Servers cache. // Servers cache.
Servers map[string]*cachemodels.Server Servers map[string]*cachemodels.Server
// Servers cache mutex. // Servers cache mutex.
ServersMutex sync.Mutex ServersMutex sync.Mutex
} }
func (c *Cache) Initialize() { func (c *Cache) Initialize() {
fmt.Println("Initializing cache...") fmt.Println("Initializing cache...")
c.initializeStorages() c.initializeStorages()
c.LoadServers(map[string]string{}) c.LoadServers(map[string]string{})
Eventer.AddEventHandler("deleteProfile", c.deleteProfile) Eventer.AddEventHandler("deleteProfile", c.deleteProfile)
Eventer.AddEventHandler("flushProfiles", c.FlushProfiles) Eventer.AddEventHandler("flushProfiles", c.FlushProfiles)
Eventer.AddEventHandler("loadProfiles", c.LoadProfiles) Eventer.AddEventHandler("loadProfiles", c.LoadProfiles)
Eventer.AddEventHandler("flushServers", c.FlushServers) Eventer.AddEventHandler("flushServers", c.FlushServers)
Eventer.AddEventHandler("loadServersIntoCache", c.LoadServers) Eventer.AddEventHandler("loadServersIntoCache", c.LoadServers)
} }
func (c *Cache) initializeStorages() { func (c *Cache) initializeStorages() {
// Profiles cache. // Profiles cache.
c.Profiles = make(map[string]*cachemodels.Profile) c.Profiles = make(map[string]*cachemodels.Profile)
// Servers cache. // Servers cache.
c.Servers = make(map[string]*cachemodels.Server) c.Servers = make(map[string]*cachemodels.Server)
} }

View File

@ -10,105 +10,105 @@
package cache package cache
import ( import (
// stdlib // stdlib
"fmt" "fmt"
"strconv" "strconv"
// local // local
"github.com/pztrn/urtrator/cachemodels" "gitlab.com/pztrn/urtrator/cachemodels"
"github.com/pztrn/urtrator/datamodels" "gitlab.com/pztrn/urtrator/datamodels"
) )
func (c *Cache) CreateProfile(name string) { func (c *Cache) CreateProfile(name string) {
fmt.Println("Creating profile " + name) fmt.Println("Creating profile " + name)
_, ok := c.Profiles[name] _, ok := c.Profiles[name]
if !ok { if !ok {
c.ProfilesMutex.Lock() c.ProfilesMutex.Lock()
c.Profiles[name] = &cachemodels.Profile{} c.Profiles[name] = &cachemodels.Profile{}
c.Profiles[name].Profile = &datamodels.Profile{} c.Profiles[name].Profile = &datamodels.Profile{}
c.ProfilesMutex.Unlock() c.ProfilesMutex.Unlock()
} }
} }
func (c *Cache) deleteProfile(data map[string]string) { func (c *Cache) deleteProfile(data map[string]string) {
fmt.Println("Deleting profile " + data["profile_name"]) fmt.Println("Deleting profile " + data["profile_name"])
c.ProfilesMutex.Lock() c.ProfilesMutex.Lock()
_, ok := c.Profiles[data["profile_name"]] _, ok := c.Profiles[data["profile_name"]]
c.ProfilesMutex.Unlock() c.ProfilesMutex.Unlock()
if ok { if ok {
c.ProfilesMutex.Lock() c.ProfilesMutex.Lock()
delete(c.Profiles, data["profile_name"]) delete(c.Profiles, data["profile_name"])
c.ProfilesMutex.Unlock() c.ProfilesMutex.Unlock()
} }
c.ProfilesMutex.Lock() c.ProfilesMutex.Lock()
_, ok1 := c.Profiles[data["profile_name"]] _, ok1 := c.Profiles[data["profile_name"]]
c.ProfilesMutex.Unlock() c.ProfilesMutex.Unlock()
if !ok1 { if !ok1 {
Database.Db.MustExec(Database.Db.Rebind("DELETE FROM urt_profiles WHERE name=?"), data["profile_name"]) Database.Db.MustExec(Database.Db.Rebind("DELETE FROM urt_profiles WHERE name=?"), data["profile_name"])
fmt.Println("Profile deleted") fmt.Println("Profile deleted")
} else { } else {
fmt.Println("Something goes wrong! Profile is still here!") fmt.Println("Something goes wrong! Profile is still here!")
} }
} }
func (c *Cache) FlushProfiles(data map[string]string) { func (c *Cache) FlushProfiles(data map[string]string) {
fmt.Println("Flushing profiles to database...") fmt.Println("Flushing profiles to database...")
raw_profiles := []datamodels.Profile{} raw_profiles := []datamodels.Profile{}
err := Database.Db.Select(&raw_profiles, "SELECT * FROM urt_profiles") err := Database.Db.Select(&raw_profiles, "SELECT * FROM urt_profiles")
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
cached_profiles := make(map[string]*datamodels.Profile) cached_profiles := make(map[string]*datamodels.Profile)
for i := range raw_profiles { for i := range raw_profiles {
cached_profiles[raw_profiles[i].Name] = c.Profiles[raw_profiles[i].Name].Profile cached_profiles[raw_profiles[i].Name] = c.Profiles[raw_profiles[i].Name].Profile
} }
new_profiles := make(map[string]*datamodels.Profile) new_profiles := make(map[string]*datamodels.Profile)
c.ProfilesMutex.Lock() c.ProfilesMutex.Lock()
for _, profile := range c.Profiles { for _, profile := range c.Profiles {
_, ok := cached_profiles[profile.Profile.Name] _, ok := cached_profiles[profile.Profile.Name]
if !ok { if !ok {
fmt.Println("Flushing new profile " + profile.Profile.Name) fmt.Println("Flushing new profile " + profile.Profile.Name)
new_profiles[profile.Profile.Name] = profile.Profile new_profiles[profile.Profile.Name] = profile.Profile
} }
} }
c.ProfilesMutex.Unlock() c.ProfilesMutex.Unlock()
tx := Database.Db.MustBegin() tx := Database.Db.MustBegin()
fmt.Println("Adding new profiles...") fmt.Println("Adding new profiles...")
for _, profile := range new_profiles { for _, profile := range new_profiles {
tx.NamedExec("INSERT INTO urt_profiles (name, version, binary, second_x_session, additional_parameters, profile_path) VALUES (:name, :version, :binary, :second_x_session, :additional_parameters, :profile_path)", &profile) tx.NamedExec("INSERT INTO urt_profiles (name, version, binary, second_x_session, additional_parameters, profile_path) VALUES (:name, :version, :binary, :second_x_session, :additional_parameters, :profile_path)", &profile)
} }
fmt.Println("Updating existing profiles...") fmt.Println("Updating existing profiles...")
for _, profile := range cached_profiles { for _, profile := range cached_profiles {
fmt.Println(fmt.Sprintf("%+v", profile)) fmt.Println(fmt.Sprintf("%+v", profile))
tx.NamedExec("UPDATE urt_profiles SET name=:name, version=:version, binary=:binary, second_x_session=:second_x_session, additional_parameters=:additional_parameters, profile_path=:profile_path WHERE name=:name", &profile) tx.NamedExec("UPDATE urt_profiles SET name=:name, version=:version, binary=:binary, second_x_session=:second_x_session, additional_parameters=:additional_parameters, profile_path=:profile_path WHERE name=:name", &profile)
} }
tx.Commit() tx.Commit()
fmt.Println("Done") fmt.Println("Done")
} }
func (c *Cache) LoadProfiles(data map[string]string) { func (c *Cache) LoadProfiles(data map[string]string) {
fmt.Println("Loading profiles to cache...") fmt.Println("Loading profiles to cache...")
raw_profiles := []datamodels.Profile{} raw_profiles := []datamodels.Profile{}
err := Database.Db.Select(&raw_profiles, "SELECT * FROM urt_profiles") err := Database.Db.Select(&raw_profiles, "SELECT * FROM urt_profiles")
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
c.ProfilesMutex.Lock() c.ProfilesMutex.Lock()
for _, profile := range raw_profiles { for _, profile := range raw_profiles {
c.Profiles[profile.Name] = &cachemodels.Profile{} c.Profiles[profile.Name] = &cachemodels.Profile{}
c.Profiles[profile.Name].Profile = &profile c.Profiles[profile.Name].Profile = &profile
} }
c.ProfilesMutex.Unlock() c.ProfilesMutex.Unlock()
fmt.Println("Load completed. Loaded " + strconv.Itoa(len(c.Profiles)) + " profiles.") fmt.Println("Load completed. Loaded " + strconv.Itoa(len(c.Profiles)) + " profiles.")
} }

228
cache/cache_servers.go vendored
View File

@ -10,135 +10,135 @@
package cache package cache
import ( import (
// stdlib // stdlib
"fmt" "fmt"
// local // local
"github.com/pztrn/urtrator/cachemodels" "gitlab.com/pztrn/urtrator/cachemodels"
"github.com/pztrn/urtrator/datamodels" "gitlab.com/pztrn/urtrator/datamodels"
) )
func (c *Cache) CreateServer(addr string) { func (c *Cache) CreateServer(addr string) {
_, ok := c.Servers[addr] _, ok := c.Servers[addr]
if !ok { if !ok {
c.ServersMutex.Lock() c.ServersMutex.Lock()
c.Servers[addr] = &cachemodels.Server{} c.Servers[addr] = &cachemodels.Server{}
c.Servers[addr].Server = &datamodels.Server{} c.Servers[addr].Server = &datamodels.Server{}
c.ServersMutex.Unlock() c.ServersMutex.Unlock()
} else { } else {
fmt.Println("Server " + addr + " already exist.") fmt.Println("Server " + addr + " already exist.")
} }
} }
// Flush servers to database. // Flush servers to database.
func (c *Cache) FlushServers(data map[string]string) { func (c *Cache) FlushServers(data map[string]string) {
fmt.Println("Updating servers information in database...") fmt.Println("Updating servers information in database...")
raw_cached := []datamodels.Server{} raw_cached := []datamodels.Server{}
Database.Db.Select(&raw_cached, "SELECT * FROM servers") Database.Db.Select(&raw_cached, "SELECT * FROM servers")
// Create map[string]*datamodels.Server once, so we won't iterate // Create map[string]*datamodels.Server once, so we won't iterate
// over slice of datamodels.Server everytime. // over slice of datamodels.Server everytime.
cached_servers := make(map[string]*datamodels.Server) cached_servers := make(map[string]*datamodels.Server)
for s := range raw_cached { for s := range raw_cached {
mapping_item_name := raw_cached[s].Ip + ":" + raw_cached[s].Port mapping_item_name := raw_cached[s].Ip + ":" + raw_cached[s].Port
cached_servers[mapping_item_name] = &raw_cached[s] cached_servers[mapping_item_name] = &raw_cached[s]
} }
new_servers := make(map[string]*datamodels.Server) new_servers := make(map[string]*datamodels.Server)
// Update our cached mapping. // Update our cached mapping.
for _, s := range c.Servers { for _, s := range c.Servers {
mapping_item_name := s.Server.Ip + ":" + s.Server.Port mapping_item_name := s.Server.Ip + ":" + s.Server.Port
_, ok := cached_servers[mapping_item_name] _, ok := cached_servers[mapping_item_name]
if !ok { if !ok {
fmt.Println(mapping_item_name + " not found!") fmt.Println(mapping_item_name + " not found!")
new_servers[mapping_item_name] = &datamodels.Server{} new_servers[mapping_item_name] = &datamodels.Server{}
new_servers[mapping_item_name].Ip = s.Server.Ip new_servers[mapping_item_name].Ip = s.Server.Ip
new_servers[mapping_item_name].Port = s.Server.Port new_servers[mapping_item_name].Port = s.Server.Port
new_servers[mapping_item_name].Name = s.Server.Name new_servers[mapping_item_name].Name = s.Server.Name
new_servers[mapping_item_name].Players = s.Server.Players new_servers[mapping_item_name].Players = s.Server.Players
new_servers[mapping_item_name].Bots = s.Server.Bots new_servers[mapping_item_name].Bots = s.Server.Bots
new_servers[mapping_item_name].Maxplayers = s.Server.Maxplayers new_servers[mapping_item_name].Maxplayers = s.Server.Maxplayers
new_servers[mapping_item_name].Ping = s.Server.Ping new_servers[mapping_item_name].Ping = s.Server.Ping
new_servers[mapping_item_name].Map = s.Server.Map new_servers[mapping_item_name].Map = s.Server.Map
new_servers[mapping_item_name].Gamemode = s.Server.Gamemode new_servers[mapping_item_name].Gamemode = s.Server.Gamemode
new_servers[mapping_item_name].Version = s.Server.Version new_servers[mapping_item_name].Version = s.Server.Version
new_servers[mapping_item_name].ExtendedConfig = s.Server.ExtendedConfig new_servers[mapping_item_name].ExtendedConfig = s.Server.ExtendedConfig
new_servers[mapping_item_name].PlayersInfo = s.Server.PlayersInfo new_servers[mapping_item_name].PlayersInfo = s.Server.PlayersInfo
new_servers[mapping_item_name].IsPrivate = s.Server.IsPrivate new_servers[mapping_item_name].IsPrivate = s.Server.IsPrivate
new_servers[mapping_item_name].Favorite = s.Server.Favorite new_servers[mapping_item_name].Favorite = s.Server.Favorite
new_servers[mapping_item_name].ProfileToUse = s.Server.ProfileToUse new_servers[mapping_item_name].ProfileToUse = s.Server.ProfileToUse
new_servers[mapping_item_name].Password = s.Server.Password new_servers[mapping_item_name].Password = s.Server.Password
} else { } else {
cached_servers[mapping_item_name].Ip = s.Server.Ip cached_servers[mapping_item_name].Ip = s.Server.Ip
cached_servers[mapping_item_name].Port = s.Server.Port cached_servers[mapping_item_name].Port = s.Server.Port
cached_servers[mapping_item_name].Name = s.Server.Name cached_servers[mapping_item_name].Name = s.Server.Name
cached_servers[mapping_item_name].Players = s.Server.Players cached_servers[mapping_item_name].Players = s.Server.Players
cached_servers[mapping_item_name].Bots = s.Server.Bots cached_servers[mapping_item_name].Bots = s.Server.Bots
cached_servers[mapping_item_name].Maxplayers = s.Server.Maxplayers cached_servers[mapping_item_name].Maxplayers = s.Server.Maxplayers
cached_servers[mapping_item_name].Ping = s.Server.Ping cached_servers[mapping_item_name].Ping = s.Server.Ping
cached_servers[mapping_item_name].Map = s.Server.Map cached_servers[mapping_item_name].Map = s.Server.Map
cached_servers[mapping_item_name].Gamemode = s.Server.Gamemode cached_servers[mapping_item_name].Gamemode = s.Server.Gamemode
cached_servers[mapping_item_name].Version = s.Server.Version cached_servers[mapping_item_name].Version = s.Server.Version
cached_servers[mapping_item_name].ExtendedConfig = s.Server.ExtendedConfig cached_servers[mapping_item_name].ExtendedConfig = s.Server.ExtendedConfig
cached_servers[mapping_item_name].PlayersInfo = s.Server.PlayersInfo cached_servers[mapping_item_name].PlayersInfo = s.Server.PlayersInfo
cached_servers[mapping_item_name].IsPrivate = s.Server.IsPrivate cached_servers[mapping_item_name].IsPrivate = s.Server.IsPrivate
cached_servers[mapping_item_name].Favorite = s.Server.Favorite cached_servers[mapping_item_name].Favorite = s.Server.Favorite
cached_servers[mapping_item_name].ProfileToUse = s.Server.ProfileToUse cached_servers[mapping_item_name].ProfileToUse = s.Server.ProfileToUse
cached_servers[mapping_item_name].Password = s.Server.Password cached_servers[mapping_item_name].Password = s.Server.Password
} }
} }
tx := Database.Db.MustBegin() tx := Database.Db.MustBegin()
fmt.Println("Adding new servers...") fmt.Println("Adding new servers...")
if len(new_servers) > 0 { if len(new_servers) > 0 {
for _, srv := range new_servers { for _, srv := range new_servers {
tx.NamedExec("INSERT INTO servers (ip, port, name, ping, players, maxplayers, gamemode, map, version, extended_config, players_info, is_private, favorite, profile_to_use, bots) VALUES (:ip, :port, :name, :ping, :players, :maxplayers, :gamemode, :map, :version, :extended_config, :players_info, :is_private, :favorite, :profile_to_use, :bots)", srv) tx.NamedExec("INSERT INTO servers (ip, port, name, ping, players, maxplayers, gamemode, map, version, extended_config, players_info, is_private, favorite, profile_to_use, bots) VALUES (:ip, :port, :name, :ping, :players, :maxplayers, :gamemode, :map, :version, :extended_config, :players_info, :is_private, :favorite, :profile_to_use, :bots)", srv)
} }
} }
fmt.Println("Updating cached servers...") fmt.Println("Updating cached servers...")
for _, srv := range cached_servers { for _, srv := range cached_servers {
_, err := tx.NamedExec("UPDATE servers SET name=:name, players=:players, maxplayers=:maxplayers, gamemode=:gamemode, map=:map, ping=:ping, version=:version, extended_config=:extended_config, favorite=:favorite, password=:password, players_info=:players_info, is_private=:is_private, profile_to_use=:profile_to_use, bots=:bots WHERE ip=:ip AND port=:port", &srv) _, err := tx.NamedExec("UPDATE servers SET name=:name, players=:players, maxplayers=:maxplayers, gamemode=:gamemode, map=:map, ping=:ping, version=:version, extended_config=:extended_config, favorite=:favorite, password=:password, players_info=:players_info, is_private=:is_private, profile_to_use=:profile_to_use, bots=:bots WHERE ip=:ip AND port=:port", &srv)
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
} }
tx.Commit() tx.Commit()
fmt.Println("Done") fmt.Println("Done")
} }
func (c *Cache) LoadServers(data map[string]string) { func (c *Cache) LoadServers(data map[string]string) {
fmt.Println("Loading servers into cache...") fmt.Println("Loading servers into cache...")
c.Servers = make(map[string]*cachemodels.Server) c.Servers = make(map[string]*cachemodels.Server)
// Getting servers from database. // Getting servers from database.
raw_servers := []datamodels.Server{} raw_servers := []datamodels.Server{}
err := Database.Db.Select(&raw_servers, "SELECT * FROM servers") err := Database.Db.Select(&raw_servers, "SELECT * FROM servers")
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
// Due to nature of pointers and goroutines thing (?) this should // Due to nature of pointers and goroutines thing (?) this should
// be done in this way. // be done in this way.
for _, server := range raw_servers { for _, server := range raw_servers {
key := server.Ip + ":" + server.Port key := server.Ip + ":" + server.Port
c.CreateServer(key) c.CreateServer(key)
c.Servers[key].Server.Name = server.Name c.Servers[key].Server.Name = server.Name
c.Servers[key].Server.Ip = server.Ip c.Servers[key].Server.Ip = server.Ip
c.Servers[key].Server.Port = server.Port c.Servers[key].Server.Port = server.Port
c.Servers[key].Server.Players = server.Players c.Servers[key].Server.Players = server.Players
c.Servers[key].Server.Bots = server.Bots c.Servers[key].Server.Bots = server.Bots
c.Servers[key].Server.Maxplayers = server.Maxplayers c.Servers[key].Server.Maxplayers = server.Maxplayers
c.Servers[key].Server.Ping = server.Ping c.Servers[key].Server.Ping = server.Ping
c.Servers[key].Server.Gamemode = server.Gamemode c.Servers[key].Server.Gamemode = server.Gamemode
c.Servers[key].Server.Map = server.Map c.Servers[key].Server.Map = server.Map
c.Servers[key].Server.Version = server.Version c.Servers[key].Server.Version = server.Version
c.Servers[key].Server.Favorite = server.Favorite c.Servers[key].Server.Favorite = server.Favorite
c.Servers[key].Server.Password = server.Password c.Servers[key].Server.Password = server.Password
c.Servers[key].Server.ProfileToUse = server.ProfileToUse c.Servers[key].Server.ProfileToUse = server.ProfileToUse
c.Servers[key].Server.ExtendedConfig = server.ExtendedConfig c.Servers[key].Server.ExtendedConfig = server.ExtendedConfig
c.Servers[key].Server.PlayersInfo = server.PlayersInfo c.Servers[key].Server.PlayersInfo = server.PlayersInfo
c.Servers[key].Server.IsPrivate = server.IsPrivate c.Servers[key].Server.IsPrivate = server.IsPrivate
} }
fmt.Println("Load completed.") fmt.Println("Load completed.")
} }

18
cache/exported.go vendored
View File

@ -10,19 +10,19 @@
package cache package cache
import ( import (
// local // local
event "github.com/pztrn/urtrator/eventer" "gitlab.com/pztrn/urtrator/database"
"github.com/pztrn/urtrator/database" event "gitlab.com/pztrn/urtrator/eventer"
) )
var ( var (
Database *database.Database Database *database.Database
Eventer *event.Eventer Eventer *event.Eventer
) )
func New(d *database.Database, e *event.Eventer) *Cache { func New(d *database.Database, e *event.Eventer) *Cache {
Database = d Database = d
Eventer = e Eventer = e
c := Cache{} c := Cache{}
return &c return &c
} }

View File

@ -10,10 +10,10 @@
package cachemodels package cachemodels
import ( import (
// local // local
"github.com/pztrn/urtrator/datamodels" "gitlab.com/pztrn/urtrator/datamodels"
) )
type Profile struct { type Profile struct {
Profile *datamodels.Profile Profile *datamodels.Profile
} }

View File

@ -10,20 +10,20 @@
package cachemodels package cachemodels
import ( import (
// local // local
"github.com/pztrn/urtrator/datamodels" "gitlab.com/pztrn/urtrator/datamodels"
// Other // Other
"github.com/mattn/go-gtk/gtk" "github.com/mattn/go-gtk/gtk"
) )
type Server struct { type Server struct {
Server *datamodels.Server Server *datamodels.Server
AllServersIter *gtk.TreeIter AllServersIter *gtk.TreeIter
AllServersIterSet bool AllServersIterSet bool
AllServersIterInList bool AllServersIterInList bool
FavServersIter *gtk.TreeIter FavServersIter *gtk.TreeIter
FavServersIterSet bool FavServersIterSet bool
FavServersIterInList bool FavServersIterInList bool
} }

View File

@ -9,20 +9,20 @@
// ToDo: put full text of license here. // ToDo: put full text of license here.
package clipboardwatcher package clipboardwatcher
import( import (
// local // local
"github.com/pztrn/urtrator/cache" "gitlab.com/pztrn/urtrator/cache"
"github.com/pztrn/urtrator/eventer" "gitlab.com/pztrn/urtrator/eventer"
) )
var ( var (
Cache *cache.Cache Cache *cache.Cache
Eventer *eventer.Eventer Eventer *eventer.Eventer
) )
func New(c *cache.Cache, e *eventer.Eventer) *ClipboardWatcher { func New(c *cache.Cache, e *eventer.Eventer) *ClipboardWatcher {
Cache = c Cache = c
Eventer = e Eventer = e
cw := ClipboardWatcher{} cw := ClipboardWatcher{}
return &cw return &cw
} }

View File

@ -10,125 +10,125 @@
package context package context
import ( import (
// stdlib // stdlib
"errors" "errors"
"fmt" "fmt"
// local // local
"github.com/pztrn/urtrator/cache" "gitlab.com/pztrn/urtrator/cache"
"github.com/pztrn/urtrator/clipboardwatcher" "gitlab.com/pztrn/urtrator/clipboardwatcher"
"github.com/pztrn/urtrator/colorizer" "gitlab.com/pztrn/urtrator/colorizer"
"github.com/pztrn/urtrator/configuration" "gitlab.com/pztrn/urtrator/configuration"
"github.com/pztrn/urtrator/database" "gitlab.com/pztrn/urtrator/database"
"github.com/pztrn/urtrator/eventer" "gitlab.com/pztrn/urtrator/eventer"
"github.com/pztrn/urtrator/launcher" "gitlab.com/pztrn/urtrator/launcher"
"github.com/pztrn/urtrator/requester" "gitlab.com/pztrn/urtrator/requester"
"github.com/pztrn/urtrator/timer" "gitlab.com/pztrn/urtrator/timer"
"github.com/pztrn/urtrator/translator" "gitlab.com/pztrn/urtrator/translator"
// Github // Github
"github.com/mattn/go-gtk/gtk" "github.com/mattn/go-gtk/gtk"
) )
type Context struct { type Context struct {
// Caching. // Caching.
Cache *cache.Cache Cache *cache.Cache
// Clipboard watcher. // Clipboard watcher.
Clipboard *clipboardwatcher.ClipboardWatcher Clipboard *clipboardwatcher.ClipboardWatcher
// Colors parser and prettifier. // Colors parser and prettifier.
Colorizer *colorizer.Colorizer Colorizer *colorizer.Colorizer
// Configuration. // Configuration.
Cfg *configuration.Config Cfg *configuration.Config
// Database. // Database.
Database *database.Database Database *database.Database
// Eventer. // Eventer.
Eventer *eventer.Eventer Eventer *eventer.Eventer
// Game launcher. // Game launcher.
Launcher *launcher.Launcher Launcher *launcher.Launcher
// Requester, which requests server's information. // Requester, which requests server's information.
Requester *requester.Requester Requester *requester.Requester
// Timer. // Timer.
Timer *timer.Timer Timer *timer.Timer
// Translator. // Translator.
Translator *translator.Translator Translator *translator.Translator
} }
func (ctx *Context) Close() error { func (ctx *Context) Close() error {
fmt.Println("Closing URTrator...") fmt.Println("Closing URTrator...")
launched := ctx.Launcher.CheckForLaunchedUrbanTerror() launched := ctx.Launcher.CheckForLaunchedUrbanTerror()
if launched != nil { if launched != nil {
return errors.New("Urban Terror is launched!") return errors.New("Urban Terror is launched!")
} }
ctx.Cache.FlushProfiles(map[string]string{}) ctx.Cache.FlushProfiles(map[string]string{})
ctx.Cache.FlushServers(map[string]string{}) ctx.Cache.FlushServers(map[string]string{})
ctx.Database.Close() ctx.Database.Close()
// At last, close main window. // At last, close main window.
gtk.MainQuit() gtk.MainQuit()
return nil return nil
} }
func (ctx *Context) initializeCache() { func (ctx *Context) initializeCache() {
ctx.Cache = cache.New(ctx.Database, ctx.Eventer) ctx.Cache = cache.New(ctx.Database, ctx.Eventer)
ctx.Cache.Initialize() ctx.Cache.Initialize()
} }
func (ctx *Context) InitializeClipboardWatcher() { func (ctx *Context) InitializeClipboardWatcher() {
ctx.Clipboard = clipboardwatcher.New(ctx.Cache, ctx.Eventer) ctx.Clipboard = clipboardwatcher.New(ctx.Cache, ctx.Eventer)
ctx.Clipboard.Initialize() ctx.Clipboard.Initialize()
} }
func (ctx *Context) initializeColorizer() { func (ctx *Context) initializeColorizer() {
ctx.Colorizer = colorizer.New() ctx.Colorizer = colorizer.New()
ctx.Colorizer.Initialize() ctx.Colorizer.Initialize()
} }
func (ctx *Context) initializeConfig() { func (ctx *Context) initializeConfig() {
ctx.Cfg = configuration.New() ctx.Cfg = configuration.New()
ctx.Cfg.Initialize() ctx.Cfg.Initialize()
} }
func (ctx *Context) initializeDatabase() { func (ctx *Context) initializeDatabase() {
ctx.Database = database.New(ctx.Cfg) ctx.Database = database.New(ctx.Cfg)
ctx.Database.Initialize(ctx.Cfg) ctx.Database.Initialize(ctx.Cfg)
ctx.Database.Migrate() ctx.Database.Migrate()
} }
func (ctx *Context) initializeEventer() { func (ctx *Context) initializeEventer() {
ctx.Eventer = eventer.New() ctx.Eventer = eventer.New()
ctx.Eventer.Initialize() ctx.Eventer.Initialize()
} }
func (ctx *Context) initializeLauncher() { func (ctx *Context) initializeLauncher() {
ctx.Launcher = launcher.New() ctx.Launcher = launcher.New()
ctx.Launcher.Initialize() ctx.Launcher.Initialize()
} }
func (ctx *Context) initializeRequester() { func (ctx *Context) initializeRequester() {
ctx.Requester = requester.New(ctx.Cache, ctx.Eventer, ctx.Cfg, ctx.Timer) ctx.Requester = requester.New(ctx.Cache, ctx.Eventer, ctx.Cfg, ctx.Timer)
ctx.Requester.Initialize() ctx.Requester.Initialize()
} }
func (ctx *Context) initializeTimer() { func (ctx *Context) initializeTimer() {
ctx.Timer = timer.New(ctx.Eventer, ctx.Cfg) ctx.Timer = timer.New(ctx.Eventer, ctx.Cfg)
ctx.Timer.Initialize() ctx.Timer.Initialize()
} }
func (ctx *Context) initializeTranslator() { func (ctx *Context) initializeTranslator() {
ctx.Translator = translator.New(ctx.Cfg) ctx.Translator = translator.New(ctx.Cfg)
ctx.Translator.Initialize() ctx.Translator.Initialize()
} }
func (ctx *Context) Initialize() { func (ctx *Context) Initialize() {
fmt.Println("Initializing application context...") fmt.Println("Initializing application context...")
ctx.initializeColorizer() ctx.initializeColorizer()
ctx.initializeConfig() ctx.initializeConfig()
ctx.initializeDatabase() ctx.initializeDatabase()
ctx.initializeTranslator() ctx.initializeTranslator()
ctx.initializeEventer() ctx.initializeEventer()
ctx.initializeCache() ctx.initializeCache()
ctx.initializeLauncher() ctx.initializeLauncher()
ctx.initializeTimer() ctx.initializeTimer()
ctx.initializeRequester() ctx.initializeRequester()
} }

View File

@ -10,85 +10,84 @@
package database package database
import ( import (
// stdlib // stdlib
//"database/sql" //"database/sql"
"fmt" "fmt"
"path" "path"
"runtime" "runtime"
"strconv" "strconv"
// local // local
"github.com/pztrn/urtrator/configuration" "gitlab.com/pztrn/urtrator/configuration"
"github.com/pztrn/urtrator/datamodels" "gitlab.com/pztrn/urtrator/datamodels"
// Other // Other
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
type Database struct { type Database struct {
// Configuration. // Configuration.
cfg *configuration.Config cfg *configuration.Config
// Pointer to initialized database connection. // Pointer to initialized database connection.
Db *sqlx.DB Db *sqlx.DB
} }
func (d *Database) Close() { func (d *Database) Close() {
fmt.Println("Closing database...") fmt.Println("Closing database...")
// Save configuration. // Save configuration.
// Delete previous configuration. // Delete previous configuration.
d.Db.MustExec("DELETE FROM configuration") d.Db.MustExec("DELETE FROM configuration")
tx := d.Db.MustBegin() tx := d.Db.MustBegin()
for k, v := range cfg.Cfg { for k, v := range cfg.Cfg {
cfg_item := datamodels.Configuration{} cfg_item := datamodels.Configuration{}
cfg_item.Key = k cfg_item.Key = k
cfg_item.Value = v cfg_item.Value = v
tx.NamedExec("INSERT INTO configuration (key, value) VALUES (:key, :value)", &cfg_item) tx.NamedExec("INSERT INTO configuration (key, value) VALUES (:key, :value)", &cfg_item)
} }
tx.Commit() tx.Commit()
d.Db.Close() d.Db.Close()
runtime.UnlockOSThread() runtime.UnlockOSThread()
} }
func (d *Database) Initialize(cfg *configuration.Config) { func (d *Database) Initialize(cfg *configuration.Config) {
fmt.Println("Initializing database...") fmt.Println("Initializing database...")
runtime.LockOSThread() runtime.LockOSThread()
// Connect to database. // Connect to database.
db_path := path.Join(cfg.TEMP["DATA"], "database.sqlite3") db_path := path.Join(cfg.TEMP["DATA"], "database.sqlite3")
fmt.Println("Database path: " + db_path) fmt.Println("Database path: " + db_path)
db, err := sqlx.Connect("sqlite3", db_path) db, err := sqlx.Connect("sqlite3", db_path)
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
d.Db = db d.Db = db
// Load configuration. // Load configuration.
cfgs := []datamodels.Configuration{} cfgs := []datamodels.Configuration{}
d.Db.Select(&cfgs, "SELECT * FROM configuration") d.Db.Select(&cfgs, "SELECT * FROM configuration")
if len(cfgs) > 0 { if len(cfgs) > 0 {
for i := range cfgs { for i := range cfgs {
cfg.Cfg[cfgs[i].Key] = cfgs[i].Value cfg.Cfg[cfgs[i].Key] = cfgs[i].Value
} }
} }
} }
func (d *Database) Migrate() { func (d *Database) Migrate() {
// Getting current database version. // Getting current database version.
dbver := 0 dbver := 0
database := []datamodels.Database{} database := []datamodels.Database{}
d.Db.Select(&database, "SELECT * FROM database") d.Db.Select(&database, "SELECT * FROM database")
if len(database) > 0 { if len(database) > 0 {
fmt.Println("Current database version: " + database[0].Version) fmt.Println("Current database version: " + database[0].Version)
dbver, _ = strconv.Atoi(database[0].Version) dbver, _ = strconv.Atoi(database[0].Version)
} else { } else {
fmt.Println("No database found, will create new one") fmt.Println("No database found, will create new one")
} }
migrate_full(d, dbver)
migrate_full(d, dbver)
} }

View File

@ -10,16 +10,16 @@
package database package database
import ( import (
// Local // Local
"github.com/pztrn/urtrator/configuration" "gitlab.com/pztrn/urtrator/configuration"
) )
var ( var (
cfg *configuration.Config cfg *configuration.Config
) )
func New(c *configuration.Config) *Database { func New(c *configuration.Config) *Database {
cfg = c cfg = c
d := Database{} d := Database{}
return &d return &d
} }

View File

@ -51,14 +51,14 @@ fi
# Okay, let's compile. # Okay, let's compile.
echo "Getting URTrator (and dependencies) sources" echo "Getting URTrator (and dependencies) sources"
go get -u -v -d github.com/pztrn/urtrator go get -u -v -d gitlab.com/pztrn/urtrator
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Failed to get URTrator sources" echo "Failed to get URTrator sources"
exit 1 exit 1
fi fi
echo "Building URTrator..." echo "Building URTrator..."
go install -v github.com/pztrn/urtrator go install -v gitlab.com/pztrn/urtrator
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Failed to build URTrator! Please, create a new bug report at https://github.com/pztrn/urtrator and attach FULL console output!" echo "Failed to build URTrator! Please, create a new bug report at https://github.com/pztrn/urtrator and attach FULL console output!"
exit 1 exit 1
@ -69,7 +69,7 @@ mkdir -p URTrator.app/Contents/{MacOS,Framework,Resources}
# Copying URTrator binary # Copying URTrator binary
cp $GOPATH/bin/urtrator URTrator.app/Contents/MacOS/ cp $GOPATH/bin/urtrator URTrator.app/Contents/MacOS/
# Copying main resources. # Copying main resources.
cp $GOPATH/src/github.com/pztrn/urtrator/artwork/urtrator.icns ./URTrator.app/Contents/Resources/ cp $GOPATH/src/gitlab.com/pztrn/urtrator/artwork/urtrator.icns ./URTrator.app/Contents/Resources/
cp -R ./Resources/themes ./URTrator.app/Contents/Resources/ cp -R ./Resources/themes ./URTrator.app/Contents/Resources/
##################################################################### #####################################################################
@ -90,7 +90,7 @@ INFOPLIST='<?xml version="1.0" encoding="UTF-8"?>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>urtrator.icns</string> <string>urtrator.icns</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.1.0</string> <string>0.2.0</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>

View File

@ -10,128 +10,128 @@
package launcher package launcher
import ( import (
// stdlib // stdlib
"errors" "errors"
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
// local // local
"github.com/pztrn/urtrator/datamodels" "gitlab.com/pztrn/urtrator/datamodels"
// Github // Github
"github.com/mattn/go-gtk/gtk" "github.com/mattn/go-gtk/gtk"
) )
type Launcher struct { type Launcher struct {
// Flags. // Flags.
// Is Urban Terror launched ATM? // Is Urban Terror launched ATM?
launched bool launched bool
} }
func (l *Launcher) CheckForLaunchedUrbanTerror() error { func (l *Launcher) CheckForLaunchedUrbanTerror() error {
if l.launched { if l.launched {
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := "Game is launched.\n\nCannot quit, because game is launched.\nQuit Urban Terror to exit URTrator!" mbox_string := "Game is launched.\n\nCannot quit, because game is launched.\nQuit Urban Terror to exit URTrator!"
m := gtk.NewMessageDialog(nil, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) m := gtk.NewMessageDialog(nil, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() { m.Response(func() {
m.Destroy() m.Destroy()
}) })
m.Run() m.Run()
return errors.New("User didn't select valid profile, mismatch with server's version.") return errors.New("User didn't select valid profile, mismatch with server's version.")
} }
} }
return nil return nil
} }
func (l *Launcher) findFreeDisplay() string { func (l *Launcher) findFreeDisplay() string {
current_display_raw := os.Getenv("DISPLAY") current_display_raw := os.Getenv("DISPLAY")
current_display, _ := strconv.Atoi(strings.Split(current_display_raw, ":")[1]) current_display, _ := strconv.Atoi(strings.Split(current_display_raw, ":")[1])
current_display += 1 current_display += 1
return strconv.Itoa(current_display) return strconv.Itoa(current_display)
} }
func (l *Launcher) Initialize() { func (l *Launcher) Initialize() {
fmt.Println("Initializing game launcher...") fmt.Println("Initializing game launcher...")
} }
func (l *Launcher) Launch(server_profile *datamodels.Server, user_profile *datamodels.Profile, password string, additional_parameters []string, callback func()) { func (l *Launcher) Launch(server_profile *datamodels.Server, user_profile *datamodels.Profile, password string, additional_parameters []string, callback func()) {
// ToDo: only one instance of Urban Terror should be launched, so button // ToDo: only one instance of Urban Terror should be launched, so button
// should be disabled. // should be disabled.
fmt.Println("Launching Urban Terror...") fmt.Println("Launching Urban Terror...")
done := make(chan bool, 1) done := make(chan bool, 1)
// Create launch string. // Create launch string.
var launch_bin string = "" var launch_bin string = ""
launch_bin, err := exec.LookPath(user_profile.Binary) launch_bin, err := exec.LookPath(user_profile.Binary)
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
server_address := server_profile.Ip + ":" + server_profile.Port server_address := server_profile.Ip + ":" + server_profile.Port
var launch_params []string var launch_params []string
if len(server_address) > 0 { if len(server_address) > 0 {
launch_params = append(launch_params, "+connect", server_address) launch_params = append(launch_params, "+connect", server_address)
} }
if len(password) > 0 { if len(password) > 0 {
launch_params = append(launch_params, "+password", password) launch_params = append(launch_params, "+password", password)
} }
if len(user_profile.Additional_params) > 0 { if len(user_profile.Additional_params) > 0 {
additional_params := strings.Split(user_profile.Additional_params, " ") additional_params := strings.Split(user_profile.Additional_params, " ")
launch_params = append(launch_params, additional_params...) launch_params = append(launch_params, additional_params...)
} }
if len(additional_parameters) > 0 { if len(additional_parameters) > 0 {
for i := range additional_parameters { for i := range additional_parameters {
launch_params = append(launch_params, additional_parameters[i]) launch_params = append(launch_params, additional_parameters[i])
} }
} }
if runtime.GOOS == "linux" && user_profile.Second_x_session == "1" { if runtime.GOOS == "linux" && user_profile.Second_x_session == "1" {
launch_params = append([]string{launch_bin}, launch_params...) launch_params = append([]string{launch_bin}, launch_params...)
display := l.findFreeDisplay() display := l.findFreeDisplay()
launch_bin, err = exec.LookPath("xinit") launch_bin, err = exec.LookPath("xinit")
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
launch_params = append(launch_params, "--", ":" + display) launch_params = append(launch_params, "--", ":"+display)
} }
if runtime.GOOS == "darwin" { if runtime.GOOS == "darwin" {
// On macOS we should not start binary, but application bundle. // On macOS we should not start binary, but application bundle.
// So we will obtain app bundle path. // So we will obtain app bundle path.
bundle_path := strings.Split(launch_bin, "/Contents")[0] bundle_path := strings.Split(launch_bin, "/Contents")[0]
// and create special launch string, which involves open. // and create special launch string, which involves open.
launch_bin = "/usr/bin/open" launch_bin = "/usr/bin/open"
launch_params = append([]string{launch_bin, "-W", "-a", bundle_path, "--args"}, launch_params...) launch_params = append([]string{launch_bin, "-W", "-a", bundle_path, "--args"}, launch_params...)
} }
fmt.Println(launch_bin, launch_params) fmt.Println(launch_bin, launch_params)
go func() { go func() {
go func() { go func() {
cmd := exec.Command(launch_bin, launch_params...) cmd := exec.Command(launch_bin, launch_params...)
// This workaround is required on Windows, otherwise ioq3 // This workaround is required on Windows, otherwise ioq3
// will not find game data. // will not find game data.
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
dir := filepath.Dir(launch_bin) dir := filepath.Dir(launch_bin)
cmd.Dir = dir cmd.Dir = dir
} }
out, err1 := cmd.Output() out, err1 := cmd.Output()
if err1 != nil { if err1 != nil {
fmt.Println("Launch error: " + err1.Error()) fmt.Println("Launch error: " + err1.Error())
} }
fmt.Println(string(out)) fmt.Println(string(out))
done <- true done <- true
}() }()
select { select {
case <- done: case <-done:
callback() callback()
} }
}() }()
} }

View File

@ -10,29 +10,29 @@
package requester package requester
import ( import (
// stdlib // stdlib
"fmt" "fmt"
// local // local
"github.com/pztrn/urtrator/cache" "gitlab.com/pztrn/urtrator/cache"
"github.com/pztrn/urtrator/configuration" "gitlab.com/pztrn/urtrator/configuration"
"github.com/pztrn/urtrator/eventer" "gitlab.com/pztrn/urtrator/eventer"
"github.com/pztrn/urtrator/timer" "gitlab.com/pztrn/urtrator/timer"
) )
var ( var (
Cache *cache.Cache Cache *cache.Cache
Cfg *configuration.Config Cfg *configuration.Config
Eventer *eventer.Eventer Eventer *eventer.Eventer
Timer *timer.Timer Timer *timer.Timer
) )
func New(c *cache.Cache, e *eventer.Eventer, cc *configuration.Config, t *timer.Timer) *Requester { func New(c *cache.Cache, e *eventer.Eventer, cc *configuration.Config, t *timer.Timer) *Requester {
Cache = c Cache = c
Cfg = cc Cfg = cc
Eventer = e Eventer = e
Timer = t Timer = t
fmt.Println("Creating Requester object...") fmt.Println("Creating Requester object...")
r := Requester{} r := Requester{}
return &r return &r
} }

View File

@ -10,281 +10,281 @@
package requester package requester
import ( import (
// stdlib // stdlib
"errors" "errors"
"fmt" "fmt"
"net" "net"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
// local // local
"github.com/pztrn/urtrator/datamodels" "gitlab.com/pztrn/urtrator/datamodels"
) )
type Pooler struct { type Pooler struct {
// Maximum number of simultaneous requests running. // Maximum number of simultaneous requests running.
maxrequests int maxrequests int
// Packet prefix. // Packet prefix.
pp string pp string
// Current requests counter mutex. // Current requests counter mutex.
cur_requests_mutex sync.Mutex cur_requests_mutex sync.Mutex
} }
func (p *Pooler) Initialize() { func (p *Pooler) Initialize() {
fmt.Println("Initializing requester goroutine pooler...") fmt.Println("Initializing requester goroutine pooler...")
// ToDo: figure out how to make this work nice. // ToDo: figure out how to make this work nice.
p.maxrequests = 150 p.maxrequests = 150
_ = runtime.GOMAXPROCS(runtime.NumCPU() * 4) _ = runtime.GOMAXPROCS(runtime.NumCPU() * 4)
p.pp = "\377\377\377\377" p.pp = "\377\377\377\377"
fmt.Println("Pooler initialized") fmt.Println("Pooler initialized")
} }
func (p *Pooler) PingOneServer(server_address string) { func (p *Pooler) PingOneServer(server_address string) {
var wait sync.WaitGroup var wait sync.WaitGroup
Cache.ServersMutex.Lock() Cache.ServersMutex.Lock()
server := Cache.Servers[server_address].Server server := Cache.Servers[server_address].Server
Cache.ServersMutex.Unlock() Cache.ServersMutex.Unlock()
wait.Add(1) wait.Add(1)
go func(srv *datamodels.Server) { go func(srv *datamodels.Server) {
defer wait.Done() defer wait.Done()
p.pingServersExecutor(srv) p.pingServersExecutor(srv)
}(server) }(server)
wait.Wait() wait.Wait()
} }
// Servers pinging pooler. Should be started as goroutine to prevent // Servers pinging pooler. Should be started as goroutine to prevent
// UI blocking. // UI blocking.
func (p *Pooler) PingServers(servers_type string) { func (p *Pooler) PingServers(servers_type string) {
fmt.Println("About to ping " + servers_type + " servers...") fmt.Println("About to ping " + servers_type + " servers...")
cur_requests := 0 cur_requests := 0
var wait sync.WaitGroup var wait sync.WaitGroup
Cache.ServersMutex.Lock() Cache.ServersMutex.Lock()
for _, server_to_ping := range Cache.Servers { for _, server_to_ping := range Cache.Servers {
if servers_type == "favorites" && server_to_ping.Server.Favorite != "1" { if servers_type == "favorites" && server_to_ping.Server.Favorite != "1" {
continue continue
} }
for { for {
p.cur_requests_mutex.Lock() p.cur_requests_mutex.Lock()
if cur_requests == p.maxrequests { if cur_requests == p.maxrequests {
p.cur_requests_mutex.Unlock() p.cur_requests_mutex.Unlock()
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)
} else { } else {
p.cur_requests_mutex.Unlock() p.cur_requests_mutex.Unlock()
break break
} }
} }
wait.Add(1) wait.Add(1)
p.cur_requests_mutex.Lock() p.cur_requests_mutex.Lock()
cur_requests += 1 cur_requests += 1
p.cur_requests_mutex.Unlock() p.cur_requests_mutex.Unlock()
go func(srv *datamodels.Server) { go func(srv *datamodels.Server) {
defer wait.Done() defer wait.Done()
p.pingServersExecutor(srv) p.pingServersExecutor(srv)
p.cur_requests_mutex.Lock() p.cur_requests_mutex.Lock()
cur_requests -= 1 cur_requests -= 1
p.cur_requests_mutex.Unlock() p.cur_requests_mutex.Unlock()
}(server_to_ping.Server) }(server_to_ping.Server)
} }
wait.Wait() wait.Wait()
Cache.ServersMutex.Unlock() Cache.ServersMutex.Unlock()
} }
func (p *Pooler) pingServersExecutor(server *datamodels.Server) error { func (p *Pooler) pingServersExecutor(server *datamodels.Server) error {
srv := server.Ip + ":" + server.Port srv := server.Ip + ":" + server.Port
fmt.Println("Pinging " + srv) fmt.Println("Pinging " + srv)
// Dial to server. // Dial to server.
start_p := time.Now() start_p := time.Now()
conn_ping, err2 := net.Dial("udp", srv) conn_ping, err2 := net.Dial("udp", srv)
if err2 != nil { if err2 != nil {
fmt.Println("Error dialing to server " + srv + "!") fmt.Println("Error dialing to server " + srv + "!")
return errors.New("Error dialing to server " + srv + "!") return errors.New("Error dialing to server " + srv + "!")
} }
// Set deadline, so we won't wait forever. // Set deadline, so we won't wait forever.
ddl_ping := time.Now() ddl_ping := time.Now()
// This should be enough. Maybe, you should'n run URTrator on modem // This should be enough. Maybe, you should'n run URTrator on modem
// connections? :) // connections? :)
ddl_ping = ddl_ping.Add(time.Second * 10) ddl_ping = ddl_ping.Add(time.Second * 10)
conn_ping.SetDeadline(ddl_ping) conn_ping.SetDeadline(ddl_ping)
msg_ping := []byte(p.pp + "getinfo") msg_ping := []byte(p.pp + "getinfo")
conn_ping.Write(msg_ping) conn_ping.Write(msg_ping)
// UDP Buffer. // UDP Buffer.
var received_buf_ping []byte = make([]byte, 128) var received_buf_ping []byte = make([]byte, 128)
// Received buffer. // Received buffer.
var raw_received_ping []byte var raw_received_ping []byte
_, err := conn_ping.Read(received_buf_ping) _, err := conn_ping.Read(received_buf_ping)
if err != nil { if err != nil {
fmt.Println("PING ERROR") fmt.Println("PING ERROR")
} }
raw_received_ping = append(raw_received_ping, received_buf_ping...) raw_received_ping = append(raw_received_ping, received_buf_ping...)
conn_ping.Close() conn_ping.Close()
delta := strconv.Itoa(int(time.Since(start_p).Nanoseconds()) / 1000000) delta := strconv.Itoa(int(time.Since(start_p).Nanoseconds()) / 1000000)
server.Ping = delta server.Ping = delta
return nil return nil
} }
func (p *Pooler) UpdateOneServer(server_address string) { func (p *Pooler) UpdateOneServer(server_address string) {
var wait sync.WaitGroup var wait sync.WaitGroup
Cache.ServersMutex.Lock() Cache.ServersMutex.Lock()
server := Cache.Servers[server_address].Server server := Cache.Servers[server_address].Server
Cache.ServersMutex.Unlock() Cache.ServersMutex.Unlock()
wait.Add(1) wait.Add(1)
go func(server *datamodels.Server) { go func(server *datamodels.Server) {
defer wait.Done() defer wait.Done()
p.UpdateSpecificServer(server) p.UpdateSpecificServer(server)
}(server) }(server)
wait.Wait() wait.Wait()
p.PingOneServer(server_address) p.PingOneServer(server_address)
Eventer.LaunchEvent("flushServers", map[string]string{}) Eventer.LaunchEvent("flushServers", map[string]string{})
Eventer.LaunchEvent("loadAllServers", map[string]string{}) Eventer.LaunchEvent("loadAllServers", map[string]string{})
Eventer.LaunchEvent("loadFavoriteServers", map[string]string{}) Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
Eventer.LaunchEvent("serversUpdateCompleted", map[string]string{}) Eventer.LaunchEvent("serversUpdateCompleted", map[string]string{})
} }
func (p *Pooler) UpdateServers(servers_type string) { func (p *Pooler) UpdateServers(servers_type string) {
var wait sync.WaitGroup var wait sync.WaitGroup
Cache.ServersMutex.Lock() Cache.ServersMutex.Lock()
for _, server := range Cache.Servers { for _, server := range Cache.Servers {
if servers_type == "favorites" && server.Server.Favorite != "1" { if servers_type == "favorites" && server.Server.Favorite != "1" {
continue continue
} }
wait.Add(1) wait.Add(1)
go func(server *datamodels.Server) { go func(server *datamodels.Server) {
defer wait.Done() defer wait.Done()
p.UpdateSpecificServer(server) p.UpdateSpecificServer(server)
}(server.Server) }(server.Server)
} }
wait.Wait() wait.Wait()
Cache.ServersMutex.Unlock() Cache.ServersMutex.Unlock()
p.PingServers(servers_type) p.PingServers(servers_type)
Eventer.LaunchEvent("flushServers", map[string]string{}) Eventer.LaunchEvent("flushServers", map[string]string{})
Eventer.LaunchEvent("loadAllServers", map[string]string{}) Eventer.LaunchEvent("loadAllServers", map[string]string{})
Eventer.LaunchEvent("loadFavoriteServers", map[string]string{}) Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
Eventer.LaunchEvent("serversUpdateCompleted", map[string]string{}) Eventer.LaunchEvent("serversUpdateCompleted", map[string]string{})
} }
// Updates information about specific server. // Updates information about specific server.
func (p *Pooler) UpdateSpecificServer(server *datamodels.Server) error { func (p *Pooler) UpdateSpecificServer(server *datamodels.Server) error {
server_addr := server.Ip + ":" + server.Port server_addr := server.Ip + ":" + server.Port
fmt.Println("Updating server: " + server_addr) fmt.Println("Updating server: " + server_addr)
// Dial to server. // Dial to server.
conn, err1 := net.Dial("udp", server_addr) conn, err1 := net.Dial("udp", server_addr)
if err1 != nil { if err1 != nil {
fmt.Println("Error dialing to server " + server_addr + "!") fmt.Println("Error dialing to server " + server_addr + "!")
return errors.New("Error dialing to server " + server_addr + "!") return errors.New("Error dialing to server " + server_addr + "!")
} }
// Set deadline, so we won't wait forever. // Set deadline, so we won't wait forever.
ddl := time.Now() ddl := time.Now()
// This should be enough. Maybe, you should'n run URTrator on modem // This should be enough. Maybe, you should'n run URTrator on modem
// connections? :) // connections? :)
ddl = ddl.Add(time.Second * 2) ddl = ddl.Add(time.Second * 2)
conn.SetDeadline(ddl) conn.SetDeadline(ddl)
msg := []byte(p.pp + "getstatus") msg := []byte(p.pp + "getstatus")
conn.Write(msg) conn.Write(msg)
// UDP Buffer. // UDP Buffer.
var received_buf []byte = make([]byte, 4096) var received_buf []byte = make([]byte, 4096)
// Received buffer. // Received buffer.
var raw_received []byte var raw_received []byte
for { for {
_, err := conn.Read(received_buf) _, err := conn.Read(received_buf)
if err != nil { if err != nil {
break break
} }
raw_received = append(raw_received, received_buf...) raw_received = append(raw_received, received_buf...)
} }
conn.Close() conn.Close()
// First line is "infoResponse" string, which we should skip by // First line is "infoResponse" string, which we should skip by
// splitting response by "\n". // splitting response by "\n".
received_lines := strings.Split(string(raw_received), "\n") received_lines := strings.Split(string(raw_received), "\n")
// We have server's data! // We have server's data!
if len(received_lines) > 1 { if len(received_lines) > 1 {
srv_config := strings.Split(received_lines[1], "\\") srv_config := strings.Split(received_lines[1], "\\")
// Parse server configuration into passed server's datamodel. // Parse server configuration into passed server's datamodel.
for i := 0; i < len(srv_config); i = i + 1 { for i := 0; i < len(srv_config); i = i + 1 {
if srv_config[i] == "g_modversion" { if srv_config[i] == "g_modversion" {
server.Version = srv_config[i + 1] server.Version = srv_config[i+1]
} }
if srv_config[i] == "g_gametype" { if srv_config[i] == "g_gametype" {
server.Gamemode = srv_config[i + 1] server.Gamemode = srv_config[i+1]
} }
if srv_config[i] == "sv_maxclients" { if srv_config[i] == "sv_maxclients" {
server.Maxplayers = srv_config[i + 1] server.Maxplayers = srv_config[i+1]
} }
if srv_config[i] == "clients" { if srv_config[i] == "clients" {
server.Players = srv_config[i + 1] server.Players = srv_config[i+1]
} }
if srv_config[i] == "mapname" { if srv_config[i] == "mapname" {
server.Map = srv_config[i + 1] server.Map = srv_config[i+1]
} }
if srv_config[i] == "sv_hostname" { if srv_config[i] == "sv_hostname" {
server.Name = srv_config[i + 1] server.Name = srv_config[i+1]
} }
if srv_config[i] == "g_needpass" { if srv_config[i] == "g_needpass" {
if srv_config[i + 1] == "0" { if srv_config[i+1] == "0" {
server.IsPrivate = "0" server.IsPrivate = "0"
} else { } else {
server.IsPrivate = "1" server.IsPrivate = "1"
} }
} }
server.ExtendedConfig = received_lines[1] server.ExtendedConfig = received_lines[1]
} }
if len(received_lines) >= 2 { if len(received_lines) >= 2 {
// Here we go, players information. // Here we go, players information.
players := received_lines[2:] players := received_lines[2:]
var real_players int = 0 var real_players int = 0
var bots int = 0 var bots int = 0
// Calculate players! // Calculate players!
if len(players) == 1 && len(players[0]) > 255 { if len(players) == 1 && len(players[0]) > 255 {
server.Players = "0" server.Players = "0"
server.Bots = "0" server.Bots = "0"
} else { } else {
// Looks like we have last element to be empty, due to // Looks like we have last element to be empty, due to
// strings.Split() call before. // strings.Split() call before.
for i := range players { for i := range players {
// Get slice with data for bots-humans parsing. // Get slice with data for bots-humans parsing.
player_data := strings.Split(string(players[i]), " ") player_data := strings.Split(string(players[i]), " ")
// If slice length isn't equal 3 - this is not what // If slice length isn't equal 3 - this is not what
// we want. // we want.
if len(player_data) != 3 { if len(player_data) != 3 {
continue continue
} }
if player_data[1] == "0" { if player_data[1] == "0" {
bots++ bots++
} else { } else {
real_players++ real_players++
} }
} }
//server.Players = strconv.Itoa(len(players) - 1) //server.Players = strconv.Itoa(len(players) - 1)
server.Players = strconv.Itoa(real_players) server.Players = strconv.Itoa(real_players)
server.Bots = strconv.Itoa(bots) server.Bots = strconv.Itoa(bots)
fmt.Println(server.Players, server.Bots) fmt.Println(server.Players, server.Bots)
} }
server.PlayersInfo = strings.Join(received_lines[2:], "\\") server.PlayersInfo = strings.Join(received_lines[2:], "\\")
} }
} }
// ToDo: Calculate ping. 0 for now. // ToDo: Calculate ping. 0 for now.
server.Ping = "0" server.Ping = "0"
return nil return nil
} }

View File

@ -10,23 +10,23 @@
package timer package timer
import ( import (
// stdlib // stdlib
"fmt" "fmt"
// local // local
"github.com/pztrn/urtrator/configuration" "gitlab.com/pztrn/urtrator/configuration"
"github.com/pztrn/urtrator/eventer" "gitlab.com/pztrn/urtrator/eventer"
) )
var ( var (
Cfg *configuration.Config Cfg *configuration.Config
Eventer *eventer.Eventer Eventer *eventer.Eventer
) )
func New(e *eventer.Eventer, cc *configuration.Config) *Timer { func New(e *eventer.Eventer, cc *configuration.Config) *Timer {
Cfg = cc Cfg = cc
Eventer = e Eventer = e
fmt.Println("Creating Timer object...") fmt.Println("Creating Timer object...")
t := Timer{} t := Timer{}
return &t return &t
} }

View File

@ -10,17 +10,17 @@
package translator package translator
import ( import (
// local // local
"github.com/pztrn/urtrator/configuration" "gitlab.com/pztrn/urtrator/configuration"
) )
var ( var (
// Configuration. // Configuration.
cfg *configuration.Config cfg *configuration.Config
) )
func New(c *configuration.Config) *Translator { func New(c *configuration.Config) *Translator {
cfg = c cfg = c
t := Translator{} t := Translator{}
return &t return &t
} }

View File

@ -10,40 +10,40 @@
package ui package ui
import ( import (
// local // local
"github.com/pztrn/urtrator/common" "gitlab.com/pztrn/urtrator/common"
// other // other
"github.com/mattn/go-gtk/gtk" "github.com/mattn/go-gtk/gtk"
) )
func ShowAboutDialog() { func ShowAboutDialog() {
ad := gtk.NewAboutDialog() ad := gtk.NewAboutDialog()
ad.SetProgramName("URTrator") ad.SetProgramName("URTrator")
ad.SetComments(ctx.Translator.Translate("Urban Terror servers browser and game launcher", nil)) ad.SetComments(ctx.Translator.Translate("Urban Terror servers browser and game launcher", nil))
ad.SetVersion(common.URTRATOR_VERSION) ad.SetVersion(common.URTRATOR_VERSION)
ad.SetWebsite("http://urtrator.pztrn.name") ad.SetWebsite("https://gitlab.com/pztrn/urtrator")
ad.SetLogo(logo) ad.SetLogo(logo)
// ToDo: put it in plain text files. // ToDo: put it in plain text files.
var authors []string var authors []string
authors = append(authors, "Stanislav N. aka pztrn - project creator, main developer.") authors = append(authors, "Stanislav N. aka pztrn - project creator, main developer.")
ad.SetAuthors(authors) ad.SetAuthors(authors)
var artists []string var artists []string
artists = append(artists, "UrTConnector team, for great icons and allowing to use them.") artists = append(artists, "UrTConnector team, for great icons and allowing to use them.")
ad.SetArtists(artists) ad.SetArtists(artists)
var documenters []string var documenters []string
documenters = append(documenters, "No one at this moment") documenters = append(documenters, "No one at this moment")
ad.SetDocumenters(documenters) ad.SetDocumenters(documenters)
ad.SetCopyright("Stanislav N. aka pztrn") ad.SetCopyright("Stanislav N. aka pztrn")
ad.SetLicense(GPL_LICENSE) ad.SetLicense(GPL_LICENSE)
ad.Run() ad.Run()
ad.Destroy() ad.Destroy()
} }
var GPL_LICENSE = ` var GPL_LICENSE = `

View File

@ -10,21 +10,21 @@
package ui package ui
import ( import (
// local // local
"github.com/pztrn/urtrator/context" "gitlab.com/pztrn/urtrator/context"
// Other // Other
"github.com/mattn/go-gtk/gdkpixbuf" "github.com/mattn/go-gtk/gdkpixbuf"
) )
var ( var (
ctx *context.Context ctx *context.Context
logo *gdkpixbuf.Pixbuf logo *gdkpixbuf.Pixbuf
) )
func NewMainWindow(c *context.Context) *MainWindow { func NewMainWindow(c *context.Context) *MainWindow {
ctx = c ctx = c
m := MainWindow{} m := MainWindow{}
return &m return &m
} }

View File

@ -10,283 +10,283 @@
package ui package ui
import ( import (
// stdlib // stdlib
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"runtime" "runtime"
"strings" "strings"
// Local // Local
"github.com/pztrn/urtrator/cachemodels" "gitlab.com/pztrn/urtrator/cachemodels"
"github.com/pztrn/urtrator/common" "gitlab.com/pztrn/urtrator/common"
"github.com/pztrn/urtrator/datamodels" "gitlab.com/pztrn/urtrator/datamodels"
// Other // Other
"github.com/mattn/go-gtk/gdkpixbuf" "github.com/mattn/go-gtk/gdkpixbuf"
"github.com/mattn/go-gtk/gtk" "github.com/mattn/go-gtk/gtk"
) )
type FavoriteDialog struct { type FavoriteDialog struct {
// Widgets. // Widgets.
// Dialog's window. // Dialog's window.
window *gtk.Window window *gtk.Window
// Main vertical box. // Main vertical box.
vbox *gtk.VBox vbox *gtk.VBox
// Server name. // Server name.
server_name *gtk.Entry server_name *gtk.Entry
// Server address. // Server address.
server_address *gtk.Entry server_address *gtk.Entry
// Server password // Server password
server_password *gtk.Entry server_password *gtk.Entry
// Profile. // Profile.
profile *gtk.ComboBoxText profile *gtk.ComboBoxText
// Flags. // Flags.
// Is known server update performed? // Is known server update performed?
update bool update bool
// Data. // Data.
// Server's we're working with. // Server's we're working with.
server *datamodels.Server server *datamodels.Server
// Profiles count that was added to profiles combobox. // Profiles count that was added to profiles combobox.
profiles int profiles int
} }
func (f *FavoriteDialog) Close() {} func (f *FavoriteDialog) Close() {}
func (f *FavoriteDialog) closeByCancel() { func (f *FavoriteDialog) closeByCancel() {
f.window.Destroy() f.window.Destroy()
} }
func (f *FavoriteDialog) fill() { func (f *FavoriteDialog) fill() {
f.server_name.SetText(f.server.Name) f.server_name.SetText(f.server.Name)
f.server_address.SetText(f.server.Ip + ":" + f.server.Port) f.server_address.SetText(f.server.Ip + ":" + f.server.Port)
f.server_password.SetText(f.server.Password) f.server_password.SetText(f.server.Password)
// Profiles. // Profiles.
// Remove old profiles. // Remove old profiles.
if f.profiles > 0 { if f.profiles > 0 {
for i := 0; i <= f.profiles; i++ { for i := 0; i <= f.profiles; i++ {
f.profile.RemoveText(0) f.profile.RemoveText(0)
} }
} }
profiles := []datamodels.Profile{} profiles := []datamodels.Profile{}
err := ctx.Database.Db.Select(&profiles, "SELECT * FROM urt_profiles") err := ctx.Database.Db.Select(&profiles, "SELECT * FROM urt_profiles")
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
var idx_in_combobox int = 0 var idx_in_combobox int = 0
var idx_should_be_active int = 0 var idx_should_be_active int = 0
for p := range profiles { for p := range profiles {
if profiles[p].Version == f.server.Version { if profiles[p].Version == f.server.Version {
f.profile.AppendText(profiles[p].Name) f.profile.AppendText(profiles[p].Name)
idx_should_be_active = idx_in_combobox idx_should_be_active = idx_in_combobox
idx_in_combobox += 1 idx_in_combobox += 1
f.profiles += 1 f.profiles += 1
} }
} }
f.profile.SetActive(idx_should_be_active) f.profile.SetActive(idx_should_be_active)
} }
func (f *FavoriteDialog) InitializeNew() { func (f *FavoriteDialog) InitializeNew() {
f.update = false f.update = false
f.server = &datamodels.Server{} f.server = &datamodels.Server{}
f.profiles = 0 f.profiles = 0
f.initializeWindow() f.initializeWindow()
} }
func (f *FavoriteDialog) InitializeUpdate(server *datamodels.Server) { func (f *FavoriteDialog) InitializeUpdate(server *datamodels.Server) {
fmt.Println("Favorites updating...") fmt.Println("Favorites updating...")
f.update = true f.update = true
f.server = server f.server = server
f.profiles = 0 f.profiles = 0
f.initializeWindow() f.initializeWindow()
f.fill() f.fill()
} }
func (f *FavoriteDialog) initializeWindow() { func (f *FavoriteDialog) initializeWindow() {
f.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL) f.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
if f.update { if f.update {
f.window.SetTitle(ctx.Translator.Translate("URTrator - {{ action }} favorite server", map[string]string{"action": "Update"})) f.window.SetTitle(ctx.Translator.Translate("URTrator - {{ action }} favorite server", map[string]string{"action": "Update"}))
} else { } else {
f.window.SetTitle(ctx.Translator.Translate("URTrator - {{ action }} favorite server", map[string]string{"action": "Add"})) f.window.SetTitle(ctx.Translator.Translate("URTrator - {{ action }} favorite server", map[string]string{"action": "Add"}))
} }
f.window.Connect("destroy", f.Close) f.window.Connect("destroy", f.Close)
f.window.SetPosition(gtk.WIN_POS_CENTER) f.window.SetPosition(gtk.WIN_POS_CENTER)
f.window.SetModal(true) f.window.SetModal(true)
f.window.SetSizeRequest(400, 200) f.window.SetSizeRequest(400, 200)
f.window.SetResizable(false) f.window.SetResizable(false)
// Load program icon from base64. // Load program icon from base64.
icon_bytes, _ := base64.StdEncoding.DecodeString(common.Logo) icon_bytes, _ := base64.StdEncoding.DecodeString(common.Logo)
icon_pixbuf := gdkpixbuf.NewLoader() icon_pixbuf := gdkpixbuf.NewLoader()
icon_pixbuf.Write(icon_bytes) icon_pixbuf.Write(icon_bytes)
logo = icon_pixbuf.GetPixbuf() logo = icon_pixbuf.GetPixbuf()
f.window.SetIcon(logo) f.window.SetIcon(logo)
// Set some GTK options for this window. // Set some GTK options for this window.
gtk_opts_raw := gtk.SettingsGetDefault() gtk_opts_raw := gtk.SettingsGetDefault()
gtk_opts := gtk_opts_raw.ToGObject() gtk_opts := gtk_opts_raw.ToGObject()
gtk_opts.Set("gtk-button-images", true) gtk_opts.Set("gtk-button-images", true)
f.vbox = gtk.NewVBox(false, 0) f.vbox = gtk.NewVBox(false, 0)
table := gtk.NewTable(5, 2, false) table := gtk.NewTable(5, 2, false)
f.vbox.PackStart(table, true, true, 5) f.vbox.PackStart(table, true, true, 5)
// Server name. // Server name.
srv_name_label := gtk.NewLabel(ctx.Translator.Translate("Server name:", nil)) srv_name_label := gtk.NewLabel(ctx.Translator.Translate("Server name:", nil))
srv_name_label.SetAlignment(0, 0) srv_name_label.SetAlignment(0, 0)
table.Attach(srv_name_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5) table.Attach(srv_name_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5)
f.server_name = gtk.NewEntry() f.server_name = gtk.NewEntry()
table.Attach(f.server_name, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 5, 5) table.Attach(f.server_name, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 5, 5)
// Server address. // Server address.
srv_addr_label := gtk.NewLabel(ctx.Translator.Translate("Server address:", nil)) srv_addr_label := gtk.NewLabel(ctx.Translator.Translate("Server address:", nil))
srv_addr_label.SetAlignment(0, 0) srv_addr_label.SetAlignment(0, 0)
table.Attach(srv_addr_label, 0, 1, 1, 2, gtk.FILL, gtk.SHRINK, 5, 5) table.Attach(srv_addr_label, 0, 1, 1, 2, gtk.FILL, gtk.SHRINK, 5, 5)
srv_addr_hbox := gtk.NewHBox(false, 0) srv_addr_hbox := gtk.NewHBox(false, 0)
f.server_address = gtk.NewEntry() f.server_address = gtk.NewEntry()
srv_addr_hbox.PackStart(f.server_address, true, true, 0) srv_addr_hbox.PackStart(f.server_address, true, true, 0)
srv_addr_update_btn := gtk.NewButton() srv_addr_update_btn := gtk.NewButton()
srv_addr_update_btn.SetTooltipText(ctx.Translator.Translate("Update server information", nil)) srv_addr_update_btn.SetTooltipText(ctx.Translator.Translate("Update server information", nil))
srv_addr_update_btn_image := gtk.NewImageFromStock(gtk.STOCK_REDO, gtk.ICON_SIZE_SMALL_TOOLBAR) srv_addr_update_btn_image := gtk.NewImageFromStock(gtk.STOCK_REDO, gtk.ICON_SIZE_SMALL_TOOLBAR)
srv_addr_update_btn.SetImage(srv_addr_update_btn_image) srv_addr_update_btn.SetImage(srv_addr_update_btn_image)
srv_addr_update_btn.Clicked(f.updateServerInfo) srv_addr_update_btn.Clicked(f.updateServerInfo)
srv_addr_hbox.PackStart(srv_addr_update_btn, false, true, 5) srv_addr_hbox.PackStart(srv_addr_update_btn, false, true, 5)
if f.update { if f.update {
f.server_address.SetSensitive(false) f.server_address.SetSensitive(false)
} }
table.Attach(srv_addr_hbox, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5) table.Attach(srv_addr_hbox, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
// Server password. // Server password.
srv_pass_label := gtk.NewLabel(ctx.Translator.Translate("Password:", nil)) srv_pass_label := gtk.NewLabel(ctx.Translator.Translate("Password:", nil))
srv_pass_label.SetAlignment(0, 0) srv_pass_label.SetAlignment(0, 0)
table.Attach(srv_pass_label, 0, 1, 2, 3, gtk.FILL, gtk.SHRINK, 5, 5) table.Attach(srv_pass_label, 0, 1, 2, 3, gtk.FILL, gtk.SHRINK, 5, 5)
f.server_password = gtk.NewEntry() f.server_password = gtk.NewEntry()
table.Attach(f.server_password, 1, 2, 2, 3, gtk.FILL, gtk.FILL, 5, 5) table.Attach(f.server_password, 1, 2, 2, 3, gtk.FILL, gtk.FILL, 5, 5)
// Profile to use. // Profile to use.
profile_label := gtk.NewLabel(ctx.Translator.Translate("Profile:", nil)) profile_label := gtk.NewLabel(ctx.Translator.Translate("Profile:", nil))
profile_label.SetAlignment(0, 0) profile_label.SetAlignment(0, 0)
table.Attach(profile_label, 0, 1, 3, 4, gtk.FILL, gtk.SHRINK, 5, 5) table.Attach(profile_label, 0, 1, 3, 4, gtk.FILL, gtk.SHRINK, 5, 5)
f.profile = gtk.NewComboBoxText() f.profile = gtk.NewComboBoxText()
table.Attach(f.profile , 1, 2, 3, 4, gtk.FILL, gtk.FILL, 5, 5) table.Attach(f.profile, 1, 2, 3, 4, gtk.FILL, gtk.FILL, 5, 5)
// Invisible thing. // Invisible thing.
inv_label1 := gtk.NewLabel("") inv_label1 := gtk.NewLabel("")
table.Attach(inv_label1, 0, 1, 4, 5, gtk.EXPAND, gtk.FILL, 5, 5) table.Attach(inv_label1, 0, 1, 4, 5, gtk.EXPAND, gtk.FILL, 5, 5)
inv_label2 := gtk.NewLabel("") inv_label2 := gtk.NewLabel("")
table.Attach(inv_label2, 1, 2, 4, 5, gtk.EXPAND, gtk.FILL, 5, 5) table.Attach(inv_label2, 1, 2, 4, 5, gtk.EXPAND, gtk.FILL, 5, 5)
// Buttons hbox. // Buttons hbox.
buttons_hbox := gtk.NewHBox(false, 0) buttons_hbox := gtk.NewHBox(false, 0)
sep := gtk.NewHSeparator() sep := gtk.NewHSeparator()
buttons_hbox.PackStart(sep, true, true, 5) buttons_hbox.PackStart(sep, true, true, 5)
// OK-Cancel buttons. // OK-Cancel buttons.
cancel_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("Cancel", nil)) cancel_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("Cancel", nil))
cancel_button.Clicked(f.closeByCancel) cancel_button.Clicked(f.closeByCancel)
buttons_hbox.PackStart(cancel_button, false, true, 5) buttons_hbox.PackStart(cancel_button, false, true, 5)
ok_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("OK", nil)) ok_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("OK", nil))
ok_button.Clicked(f.saveFavorite) ok_button.Clicked(f.saveFavorite)
buttons_hbox.PackStart(ok_button, false, true, 5) buttons_hbox.PackStart(ok_button, false, true, 5)
f.vbox.PackStart(buttons_hbox, false, true, 5) f.vbox.PackStart(buttons_hbox, false, true, 5)
f.window.Add(f.vbox) f.window.Add(f.vbox)
f.window.ShowAll() f.window.ShowAll()
} }
func (f *FavoriteDialog) saveFavorite() error { func (f *FavoriteDialog) saveFavorite() error {
// Update server's information. // Update server's information.
f.server.Name = f.server_name.GetText() f.server.Name = f.server_name.GetText()
//ctx.Requester.Pooler.UpdateSpecificServer(f.server) //ctx.Requester.Pooler.UpdateSpecificServer(f.server)
if len(f.server_address.GetText()) == 0 { if len(f.server_address.GetText()) == 0 {
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("Server address is empty.\n\nServers without address cannot be added.", nil) mbox_string := ctx.Translator.Translate("Server address is empty.\n\nServers without address cannot be added.", nil)
m := gtk.NewMessageDialog(f.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) m := gtk.NewMessageDialog(f.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() { m.Response(func() {
m.Destroy() m.Destroy()
}) })
m.Run() m.Run()
} }
return errors.New("No server address specified") return errors.New("No server address specified")
} }
var port string = "" var port string = ""
if strings.Contains(f.server_address.GetText(), ":") { if strings.Contains(f.server_address.GetText(), ":") {
port = strings.Split(f.server_address.GetText(), ":")[1] port = strings.Split(f.server_address.GetText(), ":")[1]
} else { } else {
port = "27960" port = "27960"
} }
f.server.Ip = strings.Split(f.server_address.GetText(), ":")[0] f.server.Ip = strings.Split(f.server_address.GetText(), ":")[0]
f.server.Port = port f.server.Port = port
if len(f.profile.GetActiveText()) == 0 { if len(f.profile.GetActiveText()) == 0 {
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("Profile wasn't selected.\n\nPlease, select valid profile for this server.\nIf you haven't add profiles yet - you can do it\nin options on \"Urban Terror\" tab.", nil) mbox_string := ctx.Translator.Translate("Profile wasn't selected.\n\nPlease, select valid profile for this server.\nIf you haven't add profiles yet - you can do it\nin options on \"Urban Terror\" tab.", nil)
m := gtk.NewMessageDialog(f.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) m := gtk.NewMessageDialog(f.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() { m.Response(func() {
m.Destroy() m.Destroy()
}) })
m.Run() m.Run()
} }
return errors.New("No game profile specified") return errors.New("No game profile specified")
} }
fmt.Println("Saving favorite server...") fmt.Println("Saving favorite server...")
fmt.Println(fmt.Sprintf("%+v", f.server)) fmt.Println(fmt.Sprintf("%+v", f.server))
key := strings.Split(f.server_address.GetText(), ":")[0] + ":" + port key := strings.Split(f.server_address.GetText(), ":")[0] + ":" + port
// Check if server already in cache. This would replace data about it. // Check if server already in cache. This would replace data about it.
_, ok := ctx.Cache.Servers[key] _, ok := ctx.Cache.Servers[key]
if !ok { if !ok {
ctx.Cache.Servers[key] = &cachemodels.Server{} ctx.Cache.Servers[key] = &cachemodels.Server{}
ctx.Cache.Servers[key].Server = &datamodels.Server{} ctx.Cache.Servers[key].Server = &datamodels.Server{}
} }
ctx.Cache.Servers[key].Server.Ip = f.server.Ip ctx.Cache.Servers[key].Server.Ip = f.server.Ip
ctx.Cache.Servers[key].Server.Port = f.server.Port ctx.Cache.Servers[key].Server.Port = f.server.Port
ctx.Cache.Servers[key].Server.Name = f.server.Name ctx.Cache.Servers[key].Server.Name = f.server.Name
ctx.Cache.Servers[key].Server.Password = f.server_password.GetText() ctx.Cache.Servers[key].Server.Password = f.server_password.GetText()
ctx.Cache.Servers[key].Server.ProfileToUse = f.profile.GetActiveText() ctx.Cache.Servers[key].Server.ProfileToUse = f.profile.GetActiveText()
ctx.Cache.Servers[key].Server.Favorite = "1" ctx.Cache.Servers[key].Server.Favorite = "1"
ctx.Cache.Servers[key].Server.ExtendedConfig = f.server.ExtendedConfig ctx.Cache.Servers[key].Server.ExtendedConfig = f.server.ExtendedConfig
ctx.Cache.Servers[key].Server.PlayersInfo = f.server.PlayersInfo ctx.Cache.Servers[key].Server.PlayersInfo = f.server.PlayersInfo
ctx.Eventer.LaunchEvent("flushServers", map[string]string{}) ctx.Eventer.LaunchEvent("flushServers", map[string]string{})
ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{}) ctx.Eventer.LaunchEvent("loadFavoriteServers", map[string]string{})
f.window.Destroy() f.window.Destroy()
return nil return nil
} }
func (f *FavoriteDialog) updateServerInfo() { func (f *FavoriteDialog) updateServerInfo() {
fmt.Println("Updating server information...") fmt.Println("Updating server information...")
var port string = "" var port string = ""
if strings.Contains(f.server_address.GetText(), ":") { if strings.Contains(f.server_address.GetText(), ":") {
port = strings.Split(f.server_address.GetText(), ":")[1] port = strings.Split(f.server_address.GetText(), ":")[1]
} else { } else {
port = "27960" port = "27960"
} }
f.server.Ip = strings.Split(f.server_address.GetText(), ":")[0] f.server.Ip = strings.Split(f.server_address.GetText(), ":")[0]
f.server.Port = port f.server.Port = port
ctx.Requester.Pooler.UpdateSpecificServer(f.server) ctx.Requester.Pooler.UpdateSpecificServer(f.server)
f.fill() f.fill()
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,253 +1,253 @@
package ui package ui
import ( import (
// stdlib // stdlib
"errors" "errors"
"fmt" "fmt"
"runtime" "runtime"
"strings" "strings"
// Local // Local
"github.com/pztrn/urtrator/datamodels" "gitlab.com/pztrn/urtrator/datamodels"
// other // other
"github.com/mattn/go-gtk/glib" "github.com/mattn/go-gtk/glib"
"github.com/mattn/go-gtk/gtk" "github.com/mattn/go-gtk/gtk"
) )
func (m *MainWindow) launchGame() error { func (m *MainWindow) launchGame() error {
fmt.Println("Launching Urban Terror...") fmt.Println("Launching Urban Terror...")
if len(m.qc_server_address.GetText()) != 0 { if len(m.qc_server_address.GetText()) != 0 {
m.launchWithQuickConnect() m.launchWithQuickConnect()
} else { } else {
m.launchAsUsual() m.launchAsUsual()
} }
return nil return nil
} }
// Triggers if we clicked "Launch" button without any text in quick connect // Triggers if we clicked "Launch" button without any text in quick connect
// widget. // widget.
func (m *MainWindow) launchAsUsual() error { func (m *MainWindow) launchAsUsual() error {
fmt.Println("Connecting to selected server...") fmt.Println("Connecting to selected server...")
var srv_address string = "" var srv_address string = ""
// Getting server's name from list. // Getting server's name from list.
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
sel := m.all_servers.GetSelection() sel := m.all_servers.GetSelection()
model := m.all_servers.GetModel() model := m.all_servers.GetModel()
if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) {
sel = m.fav_servers.GetSelection() sel = m.fav_servers.GetSelection()
model = m.fav_servers.GetModel() model = m.fav_servers.GetModel()
} }
iter := new(gtk.TreeIter) iter := new(gtk.TreeIter)
_ = sel.GetSelected(iter) _ = sel.GetSelected(iter)
// Getting server address. // Getting server address.
var srv_addr string var srv_addr string
srv_address_gval := glib.ValueFromNative(srv_addr) srv_address_gval := glib.ValueFromNative(srv_addr)
if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) { if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) {
model.GetValue(iter, m.column_pos["Servers"]["IP"], srv_address_gval) model.GetValue(iter, m.column_pos["Servers"]["IP"], srv_address_gval)
} else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { } else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) {
model.GetValue(iter, m.column_pos["Favorites"]["IP"], srv_address_gval) model.GetValue(iter, m.column_pos["Favorites"]["IP"], srv_address_gval)
} }
srv_address = srv_address_gval.GetString() srv_address = srv_address_gval.GetString()
if len(srv_address) == 0 { if len(srv_address) == 0 {
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("No server selected.\n\nPlease, select a server to continue connecting.", nil) mbox_string := ctx.Translator.Translate("No server selected.\n\nPlease, select a server to continue connecting.", nil)
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
messagebox.Response(func() { messagebox.Response(func() {
messagebox.Destroy() messagebox.Destroy()
}) })
messagebox.Run() messagebox.Run()
} else { } else {
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("Select a server we will connect to!", nil) + "</span></markup>"}) ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("Select a server we will connect to!", nil) + "</span></markup>"})
} }
return errors.New(ctx.Translator.Translate("No server selected.", nil)) return errors.New(ctx.Translator.Translate("No server selected.", nil))
} }
server_profile := ctx.Cache.Servers[srv_address].Server server_profile := ctx.Cache.Servers[srv_address].Server
// Check for proper server name. If length == 0: server is offline, // Check for proper server name. If length == 0: server is offline,
// we should show notification to user. // we should show notification to user.
if len(server_profile.Name) == 0 { if len(server_profile.Name) == 0 {
var will_continue bool = false var will_continue bool = false
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("Selected server is offline.\n\nWould you still want to launch Urban Terror?\nIt will just launch a game, without connecting to\nany server.", nil) mbox_string := ctx.Translator.Translate("Selected server is offline.\n\nWould you still want to launch Urban Terror?\nIt will just launch a game, without connecting to\nany server.", nil)
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string) messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string)
messagebox.Connect("response", func(resp *glib.CallbackContext) { messagebox.Connect("response", func(resp *glib.CallbackContext) {
if resp.Args(0) == 4294967287 { if resp.Args(0) == 4294967287 {
will_continue = false will_continue = false
} else { } else {
will_continue = true will_continue = true
} }
messagebox.Destroy() messagebox.Destroy()
}) })
messagebox.Run() messagebox.Run()
} else { } else {
// We're okay to connect to empty server, temporary. // We're okay to connect to empty server, temporary.
will_continue = true will_continue = true
} }
if !will_continue { if !will_continue {
return errors.New(ctx.Translator.Translate("User declined to connect to offline server", nil)) return errors.New(ctx.Translator.Translate("User declined to connect to offline server", nil))
} }
} }
// Getting selected profile's name. // Getting selected profile's name.
profile_name := m.profiles.GetActiveText() profile_name := m.profiles.GetActiveText()
user_profile := &datamodels.Profile{} user_profile := &datamodels.Profile{}
if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) { if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) {
// Checking profile name length. If 0 - then stop executing :) // Checking profile name length. If 0 - then stop executing :)
// This check only relevant to "Servers" tab, favorite servers // This check only relevant to "Servers" tab, favorite servers
// have profiles defined (see next). // have profiles defined (see next).
if len(profile_name) == 0 { if len(profile_name) == 0 {
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("Invalid game profile selected.\n\nPlease, select profile and retry.", nil) mbox_string := ctx.Translator.Translate("Invalid game profile selected.\n\nPlease, select profile and retry.", nil)
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
messagebox.Response(func() { messagebox.Response(func() {
messagebox.Destroy() messagebox.Destroy()
}) })
messagebox.Run() messagebox.Run()
} else { } else {
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("Invalid game profile selected.", nil) + "</span></markup>"}) ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("Invalid game profile selected.", nil) + "</span></markup>"})
} }
return errors.New(ctx.Translator.Translate("User didn't select valid profile.", nil)) return errors.New(ctx.Translator.Translate("User didn't select valid profile.", nil))
} }
user_profile = ctx.Cache.Profiles[profile_name].Profile user_profile = ctx.Cache.Profiles[profile_name].Profile
} else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { } else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) {
// For favorite servers profile specified in favorite server // For favorite servers profile specified in favorite server
// information have higher priority, so we just override it :) // information have higher priority, so we just override it :)
user_profile_cached, ok := ctx.Cache.Profiles[server_profile.ProfileToUse] user_profile_cached, ok := ctx.Cache.Profiles[server_profile.ProfileToUse]
if !ok { if !ok {
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("Invalid game profile specified for favorite server.\n\nPlease, edit your favorite server, select valid profile and retry.", nil) mbox_string := ctx.Translator.Translate("Invalid game profile specified for favorite server.\n\nPlease, edit your favorite server, select valid profile and retry.", nil)
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
messagebox.Response(func() { messagebox.Response(func() {
messagebox.Destroy() messagebox.Destroy()
}) })
messagebox.Run() messagebox.Run()
} else { } else {
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("Invalid game profile specified in favorite entry.", nil) + "</span></markup>"}) ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("Invalid game profile specified in favorite entry.", nil) + "</span></markup>"})
} }
return errors.New(ctx.Translator.Translate("User didn't select valid profile.", nil)) return errors.New(ctx.Translator.Translate("User didn't select valid profile.", nil))
} }
user_profile = user_profile_cached.Profile user_profile = user_profile_cached.Profile
} }
m.launchActually(server_profile, user_profile, "", "") m.launchActually(server_profile, user_profile, "", "")
return nil return nil
} }
// Triggers when Launch button was clicked with some text in quick connect // Triggers when Launch button was clicked with some text in quick connect
// widget. // widget.
func (m *MainWindow) launchWithQuickConnect() error { func (m *MainWindow) launchWithQuickConnect() error {
fmt.Println("Launching game with data from quick connect...") fmt.Println("Launching game with data from quick connect...")
srv_address := m.qc_server_address.GetText() srv_address := m.qc_server_address.GetText()
srv_password := m.qc_password.GetText() srv_password := m.qc_password.GetText()
srv_nickname := m.qc_nickname.GetText() srv_nickname := m.qc_nickname.GetText()
current_profile_name := m.profiles.GetActiveText() current_profile_name := m.profiles.GetActiveText()
// As we're launching without any profile defined - we should // As we're launching without any profile defined - we should
// check server version and globally selected profile. // check server version and globally selected profile.
// Checking if we have server defined in cache. // Checking if we have server defined in cache.
var ip string = "" var ip string = ""
var port string = "" var port string = ""
if strings.Contains(srv_address, ":") { if strings.Contains(srv_address, ":") {
ip = strings.Split(srv_address, ":")[0] ip = strings.Split(srv_address, ":")[0]
port = strings.Split(srv_address, ":")[1] port = strings.Split(srv_address, ":")[1]
} else { } else {
ip = strings.Split(srv_address, ":")[0] ip = strings.Split(srv_address, ":")[0]
port = "27960" port = "27960"
} }
key := ip + ":" + port key := ip + ":" + port
_, ok := ctx.Cache.Servers[key] _, ok := ctx.Cache.Servers[key]
if !ok { if !ok {
ctx.Cache.CreateServer(key) ctx.Cache.CreateServer(key)
fmt.Println("Server not found in cache, requesting information...") fmt.Println("Server not found in cache, requesting information...")
ctx.Requester.UpdateOneServer(key) ctx.Requester.UpdateOneServer(key)
} }
server_profile := ctx.Cache.Servers[key] server_profile := ctx.Cache.Servers[key]
user_profile := ctx.Cache.Profiles[current_profile_name] user_profile := ctx.Cache.Profiles[current_profile_name]
m.launchActually(server_profile.Server, user_profile.Profile, srv_password, srv_nickname) m.launchActually(server_profile.Server, user_profile.Profile, srv_password, srv_nickname)
return nil return nil
} }
func (m *MainWindow) launchActually(server_profile *datamodels.Server, user_profile *datamodels.Profile, password string, nickname_to_use string) error { func (m *MainWindow) launchActually(server_profile *datamodels.Server, user_profile *datamodels.Profile, password string, nickname_to_use string) error {
if server_profile.Name == "" { if server_profile.Name == "" {
var will_continue bool = false var will_continue bool = false
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("Selected server is offline.\n\nWould you still want to launch Urban Terror?\nIt will just launch a game, without connecting to\nany server.", nil) mbox_string := ctx.Translator.Translate("Selected server is offline.\n\nWould you still want to launch Urban Terror?\nIt will just launch a game, without connecting to\nany server.", nil)
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string) messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_YES_NO, mbox_string)
messagebox.Connect("response", func(resp *glib.CallbackContext) { messagebox.Connect("response", func(resp *glib.CallbackContext) {
if resp.Args(0) == 4294967287 { if resp.Args(0) == 4294967287 {
will_continue = false will_continue = false
} else { } else {
will_continue = true will_continue = true
} }
messagebox.Destroy() messagebox.Destroy()
}) })
messagebox.Run() messagebox.Run()
} else { } else {
// We're ok here, temporary. // We're ok here, temporary.
will_continue = true will_continue = true
} }
if !will_continue { if !will_continue {
return errors.New(ctx.Translator.Translate("User declined to connect to offline server", nil)) return errors.New(ctx.Translator.Translate("User declined to connect to offline server", nil))
} }
} }
// Check if server is applicable for selected profile. // Check if server is applicable for selected profile.
if server_profile.Version != user_profile.Version { if server_profile.Version != user_profile.Version {
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("Invalid game profile selected.\n\nSelected profile have different game version than server.\nPlease, select valid profile and retry.", nil) mbox_string := ctx.Translator.Translate("Invalid game profile selected.\n\nSelected profile have different game version than server.\nPlease, select valid profile and retry.", nil)
messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) messagebox := gtk.NewMessageDialog(m.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
messagebox.Response(func() { messagebox.Response(func() {
messagebox.Destroy() messagebox.Destroy()
}) })
messagebox.Run() messagebox.Run()
} else { } else {
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("Invalid game profile selected.", nil) + "</span></markup>"}) ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("Invalid game profile selected.", nil) + "</span></markup>"})
} }
return errors.New(ctx.Translator.Translate("User didn't select valid profile, mismatch with server's version.", nil)) return errors.New(ctx.Translator.Translate("User didn't select valid profile, mismatch with server's version.", nil))
} }
server_password := password server_password := password
if len(server_password) == 0 { if len(server_password) == 0 {
server_password = server_profile.Password server_password = server_profile.Password
} }
// Hey, we're ok here! :) Launch Urban Terror! // Hey, we're ok here! :) Launch Urban Terror!
// Clear server name from "<markup></markup>" things. // Clear server name from "<markup></markup>" things.
srv_name_for_label := server_profile.Name srv_name_for_label := server_profile.Name
if strings.Contains(server_profile.Name, "markup") { if strings.Contains(server_profile.Name, "markup") {
srv_name_for_label = string([]byte(server_profile.Name)[8:len(server_profile.Name)-9]) srv_name_for_label = string([]byte(server_profile.Name)[8 : len(server_profile.Name)-9])
} else { } else {
srv_name := ctx.Colorizer.Fix(server_profile.Name) srv_name := ctx.Colorizer.Fix(server_profile.Name)
srv_name_for_label = string([]byte(srv_name)[8:len(srv_name)-9]) srv_name_for_label = string([]byte(srv_name)[8 : len(srv_name)-9])
} }
// Show great coloured label. // Show great coloured label.
ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("Urban Terror is launched with profile", nil) + " </span><span foreground=\"blue\">" + user_profile.Name + "</span> <span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("and connected to", nil) + " </span><span foreground=\"orange\" font_weight=\"bold\">" + srv_name_for_label + "</span></markup>"}) ctx.Eventer.LaunchEvent("setToolbarLabelText", map[string]string{"text": "<markup><span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("Urban Terror is launched with profile", nil) + " </span><span foreground=\"blue\">" + user_profile.Name + "</span> <span foreground=\"red\" font_weight=\"bold\">" + ctx.Translator.Translate("and connected to", nil) + " </span><span foreground=\"orange\" font_weight=\"bold\">" + srv_name_for_label + "</span></markup>"})
m.launch_button.SetSensitive(false) m.launch_button.SetSensitive(false)
// ToDo: handling server passwords. // ToDo: handling server passwords.
ctx.Launcher.Launch(server_profile, user_profile, server_password, []string{"+name", nickname_to_use}, m.unlockInterface) ctx.Launcher.Launch(server_profile, user_profile, server_password, []string{"+name", nickname_to_use}, m.unlockInterface)
return nil return nil
} }

View File

@ -1,96 +1,96 @@
package ui package ui
import ( import (
// stdlib // stdlib
"strconv" "strconv"
"strings" "strings"
// other // other
"github.com/mattn/go-gtk/glib" "github.com/mattn/go-gtk/glib"
"github.com/mattn/go-gtk/gtk" "github.com/mattn/go-gtk/gtk"
) )
func (m *MainWindow) sortServersByName(model *gtk.TreeModel, a *gtk.TreeIter, b *gtk.TreeIter) int { func (m *MainWindow) sortServersByName(model *gtk.TreeModel, a *gtk.TreeIter, b *gtk.TreeIter, userData interface{}) int {
var name1_raw glib.GValue var name1_raw glib.GValue
var name2_raw glib.GValue var name2_raw glib.GValue
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) { if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) {
model.GetValue(a, m.column_pos["Servers"][ctx.Translator.Translate("Name", nil)], &name1_raw) model.GetValue(a, m.column_pos["Servers"][ctx.Translator.Translate("Name", nil)], &name1_raw)
model.GetValue(b, m.column_pos["Servers"][ctx.Translator.Translate("Name", nil)], &name2_raw) model.GetValue(b, m.column_pos["Servers"][ctx.Translator.Translate("Name", nil)], &name2_raw)
} else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { } else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) {
model.GetValue(a, m.column_pos["Favorites"][ctx.Translator.Translate("Name", nil)], &name1_raw) model.GetValue(a, m.column_pos["Favorites"][ctx.Translator.Translate("Name", nil)], &name1_raw)
model.GetValue(b, m.column_pos["Favorites"][ctx.Translator.Translate("Name", nil)], &name2_raw) model.GetValue(b, m.column_pos["Favorites"][ctx.Translator.Translate("Name", nil)], &name2_raw)
} else { } else {
return 0 return 0
} }
name1 := strings.ToLower(ctx.Colorizer.ClearFromMarkup(name1_raw.GetString())) name1 := strings.ToLower(ctx.Colorizer.ClearFromMarkup(name1_raw.GetString()))
name2 := strings.ToLower(ctx.Colorizer.ClearFromMarkup(name2_raw.GetString())) name2 := strings.ToLower(ctx.Colorizer.ClearFromMarkup(name2_raw.GetString()))
if name1 < name2 { if name1 < name2 {
return -1 return -1
} else { } else {
return 1 return 1
} }
return 0 return 0
} }
func (m *MainWindow) sortServersByPlayers(model *gtk.TreeModel, a *gtk.TreeIter, b *gtk.TreeIter) int { func (m *MainWindow) sortServersByPlayers(model *gtk.TreeModel, a *gtk.TreeIter, b *gtk.TreeIter, userData interface{}) int {
var players1_raw glib.GValue var players1_raw glib.GValue
var players2_raw glib.GValue var players2_raw glib.GValue
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) { if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) {
model.GetValue(a, m.column_pos["Servers"][ctx.Translator.Translate("Players", nil)], &players1_raw) model.GetValue(a, m.column_pos["Servers"][ctx.Translator.Translate("Players", nil)], &players1_raw)
model.GetValue(b, m.column_pos["Servers"][ctx.Translator.Translate("Players", nil)], &players2_raw) model.GetValue(b, m.column_pos["Servers"][ctx.Translator.Translate("Players", nil)], &players2_raw)
} else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { } else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) {
model.GetValue(a, m.column_pos["Favorites"][ctx.Translator.Translate("Players", nil)], &players1_raw) model.GetValue(a, m.column_pos["Favorites"][ctx.Translator.Translate("Players", nil)], &players1_raw)
model.GetValue(b, m.column_pos["Favorites"][ctx.Translator.Translate("Players", nil)], &players2_raw) model.GetValue(b, m.column_pos["Favorites"][ctx.Translator.Translate("Players", nil)], &players2_raw)
} else { } else {
return 0 return 0
} }
players1_online := strings.Split(players1_raw.GetString(), "/")[0] players1_online := strings.Split(players1_raw.GetString(), "/")[0]
players2_online := strings.Split(players2_raw.GetString(), "/")[0] players2_online := strings.Split(players2_raw.GetString(), "/")[0]
if len(players1_online) > 0 && len(players2_online) > 0 { if len(players1_online) > 0 && len(players2_online) > 0 {
players1, _ := strconv.Atoi(players1_online) players1, _ := strconv.Atoi(players1_online)
players2, _ := strconv.Atoi(players2_online) players2, _ := strconv.Atoi(players2_online)
if players1 > players2 { if players1 > players2 {
return -1 return -1
} else { } else {
return 1 return 1
} }
} }
return -1 return -1
} }
func (m *MainWindow) sortServersByPing(model *gtk.TreeModel, a *gtk.TreeIter, b *gtk.TreeIter) int { func (m *MainWindow) sortServersByPing(model *gtk.TreeModel, a *gtk.TreeIter, b *gtk.TreeIter, userData interface{}) int {
var ping1_raw glib.GValue var ping1_raw glib.GValue
var ping2_raw glib.GValue var ping2_raw glib.GValue
current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage())) current_tab := m.tab_widget.GetTabLabelText(m.tab_widget.GetNthPage(m.tab_widget.GetCurrentPage()))
if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) { if strings.Contains(current_tab, ctx.Translator.Translate("Servers", nil)) {
model.GetValue(a, m.column_pos["Servers"][ctx.Translator.Translate("Ping", nil)], &ping1_raw) model.GetValue(a, m.column_pos["Servers"][ctx.Translator.Translate("Ping", nil)], &ping1_raw)
model.GetValue(b, m.column_pos["Servers"][ctx.Translator.Translate("Ping", nil)], &ping2_raw) model.GetValue(b, m.column_pos["Servers"][ctx.Translator.Translate("Ping", nil)], &ping2_raw)
} else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) { } else if strings.Contains(current_tab, ctx.Translator.Translate("Favorites", nil)) {
model.GetValue(a, m.column_pos["Favorites"][ctx.Translator.Translate("Ping", nil)], &ping1_raw) model.GetValue(a, m.column_pos["Favorites"][ctx.Translator.Translate("Ping", nil)], &ping1_raw)
model.GetValue(b, m.column_pos["Favorites"][ctx.Translator.Translate("Ping", nil)], &ping2_raw) model.GetValue(b, m.column_pos["Favorites"][ctx.Translator.Translate("Ping", nil)], &ping2_raw)
} else { } else {
return 0 return 0
} }
ping1, _ := strconv.Atoi(ping1_raw.GetString()) ping1, _ := strconv.Atoi(ping1_raw.GetString())
ping2, _ := strconv.Atoi(ping2_raw.GetString()) ping2, _ := strconv.Atoi(ping2_raw.GetString())
if ping1 < ping2 { if ping1 < ping2 {
return 1 return 1
} else { } else {
return -1 return -1
} }
return -1 return -1
} }

View File

@ -10,427 +10,427 @@
package ui package ui
import ( import (
// stdlib // stdlib
"fmt" "fmt"
"runtime" "runtime"
// Local // Local
"github.com/pztrn/urtrator/datamodels" "gitlab.com/pztrn/urtrator/datamodels"
// Other // Other
"github.com/mattn/go-gtk/gtk" "github.com/mattn/go-gtk/glib"
"github.com/mattn/go-gtk/glib" "github.com/mattn/go-gtk/gtk"
) )
type OptionsDialog struct { type OptionsDialog struct {
// Window. // Window.
window *gtk.Window window *gtk.Window
// Options main VBox. // Options main VBox.
vbox *gtk.VBox vbox *gtk.VBox
// Tabs widget. // Tabs widget.
tab_widget *gtk.Notebook tab_widget *gtk.Notebook
// Widgets. // Widgets.
// General tab. // General tab.
// Show tray icon checkbutton. // Show tray icon checkbutton.
show_tray_icon *gtk.CheckButton show_tray_icon *gtk.CheckButton
// Enable autoupdate checkbutton. // Enable autoupdate checkbutton.
autoupdate *gtk.CheckButton autoupdate *gtk.CheckButton
// Appearance tab. // Appearance tab.
// Language to use. // Language to use.
language_combo *gtk.ComboBoxText language_combo *gtk.ComboBoxText
// Urban Terror tab. // Urban Terror tab.
// Profiles list. // Profiles list.
profiles_list *gtk.TreeView profiles_list *gtk.TreeView
// Servers updating tab. // Servers updating tab.
// Master server address. // Master server address.
master_server_addr *gtk.Entry master_server_addr *gtk.Entry
// Servers autoupdate. // Servers autoupdate.
servers_autoupdate *gtk.CheckButton servers_autoupdate *gtk.CheckButton
// Timeout for servers autoupdating. // Timeout for servers autoupdating.
servers_autoupdate_timeout *gtk.Entry servers_autoupdate_timeout *gtk.Entry
// Data stores. // Data stores.
// Urban Terror profiles list. // Urban Terror profiles list.
profiles_list_store *gtk.ListStore profiles_list_store *gtk.ListStore
} }
func (o *OptionsDialog) addProfile() { func (o *OptionsDialog) addProfile() {
fmt.Println("Adding profile...") fmt.Println("Adding profile...")
op := OptionsProfile{} op := OptionsProfile{}
op.Initialize(false) op.Initialize(false)
ctx.Eventer.LaunchEvent("flushProfiles", map[string]string{}) ctx.Eventer.LaunchEvent("flushProfiles", map[string]string{})
ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{}) ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{})
ctx.Eventer.LaunchEvent("loadProfilesIntoMainWindow", map[string]string{}) ctx.Eventer.LaunchEvent("loadProfilesIntoMainWindow", map[string]string{})
} }
func (o *OptionsDialog) closeOptionsDialogByCancel() { func (o *OptionsDialog) closeOptionsDialogByCancel() {
o.window.Destroy() o.window.Destroy()
} }
func (o *OptionsDialog) closeOptionsDialogWithDiscard() { func (o *OptionsDialog) closeOptionsDialogWithDiscard() {
} }
func (o *OptionsDialog) closeOptionsDialogWithSaving() { func (o *OptionsDialog) closeOptionsDialogWithSaving() {
fmt.Println("Saving changes to options...") fmt.Println("Saving changes to options...")
o.saveGeneral() o.saveGeneral()
o.saveAppearance() o.saveAppearance()
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("Some options require application restart to be applied.", nil) mbox_string := ctx.Translator.Translate("Some options require application restart to be applied.", nil)
m := gtk.NewMessageDialog(o.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, mbox_string) m := gtk.NewMessageDialog(o.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, mbox_string)
m.Response(func() { m.Response(func() {
m.Destroy() m.Destroy()
}) })
m.Run() m.Run()
} }
o.window.Destroy() o.window.Destroy()
} }
func (o *OptionsDialog) deleteProfile() { func (o *OptionsDialog) deleteProfile() {
// Oh... dat... GTK... // Oh... dat... GTK...
sel := o.profiles_list.GetSelection() sel := o.profiles_list.GetSelection()
model := o.profiles_list.GetModel() model := o.profiles_list.GetModel()
iter := new(gtk.TreeIter) iter := new(gtk.TreeIter)
_ = sel.GetSelected(iter) _ = sel.GetSelected(iter)
var p string var p string
gval := glib.ValueFromNative(p) gval := glib.ValueFromNative(p)
model.GetValue(iter, 0, gval) model.GetValue(iter, 0, gval)
profile_name := gval.GetString() profile_name := gval.GetString()
if len(profile_name) > 0 { if len(profile_name) > 0 {
fmt.Println("Deleting profile '" + profile_name + "'") fmt.Println("Deleting profile '" + profile_name + "'")
profile := datamodels.Profile{} profile := datamodels.Profile{}
profile.Name = profile_name profile.Name = profile_name
ctx.Eventer.LaunchEvent("deleteProfile", map[string]string{"profile_name": profile_name}) ctx.Eventer.LaunchEvent("deleteProfile", map[string]string{"profile_name": profile_name})
ctx.Eventer.LaunchEvent("flushProfiles", map[string]string{}) ctx.Eventer.LaunchEvent("flushProfiles", map[string]string{})
ctx.Eventer.LaunchEvent("loadProfilesIntoMainWindow", map[string]string{}) ctx.Eventer.LaunchEvent("loadProfilesIntoMainWindow", map[string]string{})
ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{}) ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{})
} }
} }
func (o *OptionsDialog) editProfile() { func (o *OptionsDialog) editProfile() {
// Oh... dat... GTK... // Oh... dat... GTK...
sel := o.profiles_list.GetSelection() sel := o.profiles_list.GetSelection()
model := o.profiles_list.GetModel() model := o.profiles_list.GetModel()
iter := new(gtk.TreeIter) iter := new(gtk.TreeIter)
_ = sel.GetSelected(iter) _ = sel.GetSelected(iter)
var p string var p string
gval := glib.ValueFromNative(p) gval := glib.ValueFromNative(p)
model.GetValue(iter, 0, gval) model.GetValue(iter, 0, gval)
profile_name := gval.GetString() profile_name := gval.GetString()
if len(profile_name) > 0 { if len(profile_name) > 0 {
op := OptionsProfile{} op := OptionsProfile{}
op.InitializeUpdate(profile_name) op.InitializeUpdate(profile_name)
ctx.Eventer.LaunchEvent("flushProfiles", map[string]string{}) ctx.Eventer.LaunchEvent("flushProfiles", map[string]string{})
ctx.Eventer.LaunchEvent("loadProfilesIntoMainWindow", map[string]string{}) ctx.Eventer.LaunchEvent("loadProfilesIntoMainWindow", map[string]string{})
ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{}) ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{})
} }
} }
func (o *OptionsDialog) fill() { func (o *OptionsDialog) fill() {
if ctx.Cfg.Cfg["/general/show_tray_icon"] == "1" { if ctx.Cfg.Cfg["/general/show_tray_icon"] == "1" {
o.show_tray_icon.SetActive(true) o.show_tray_icon.SetActive(true)
} }
if ctx.Cfg.Cfg["/general/urtrator_autoupdate"] == "1" { if ctx.Cfg.Cfg["/general/urtrator_autoupdate"] == "1" {
o.autoupdate.SetActive(true) o.autoupdate.SetActive(true)
} }
// Servers updating tab. // Servers updating tab.
master_server_addr, ok := ctx.Cfg.Cfg["/servers_updating/master_server"] master_server_addr, ok := ctx.Cfg.Cfg["/servers_updating/master_server"]
if !ok { if !ok {
o.master_server_addr.SetText("master.urbanterror.info:27900") o.master_server_addr.SetText("master.urbanterror.info:27900")
} else { } else {
o.master_server_addr.SetText(master_server_addr) o.master_server_addr.SetText(master_server_addr)
} }
servers_autoupdate, ok1 := ctx.Cfg.Cfg["/servers_updating/servers_autoupdate"] servers_autoupdate, ok1 := ctx.Cfg.Cfg["/servers_updating/servers_autoupdate"]
if ok1 { if ok1 {
if servers_autoupdate == "1" { if servers_autoupdate == "1" {
o.servers_autoupdate.SetActive(true) o.servers_autoupdate.SetActive(true)
} }
} }
servers_update_timeout, ok2 := ctx.Cfg.Cfg["/servers_updating/servers_autoupdate_timeout"] servers_update_timeout, ok2 := ctx.Cfg.Cfg["/servers_updating/servers_autoupdate_timeout"]
if !ok2 { if !ok2 {
o.servers_autoupdate_timeout.SetText("10") o.servers_autoupdate_timeout.SetText("10")
} else { } else {
o.servers_autoupdate_timeout.SetText(servers_update_timeout) o.servers_autoupdate_timeout.SetText(servers_update_timeout)
} }
} }
// Appearance tab initialization. // Appearance tab initialization.
func (o *OptionsDialog) initializeAppearanceTab() { func (o *OptionsDialog) initializeAppearanceTab() {
appearance_vbox := gtk.NewVBox(false, 0) appearance_vbox := gtk.NewVBox(false, 0)
appearance_table := gtk.NewTable(1, 2, false) appearance_table := gtk.NewTable(1, 2, false)
language_selection_tooltip := ctx.Translator.Translate("Language which URTrator will use.\n\nChanging this requires URTrator restart!", nil) language_selection_tooltip := ctx.Translator.Translate("Language which URTrator will use.\n\nChanging this requires URTrator restart!", nil)
language_selection_label := gtk.NewLabel(ctx.Translator.Translate("Language:", nil)) language_selection_label := gtk.NewLabel(ctx.Translator.Translate("Language:", nil))
language_selection_label.SetAlignment(0, 0) language_selection_label.SetAlignment(0, 0)
language_selection_label.SetTooltipText(language_selection_tooltip) language_selection_label.SetTooltipText(language_selection_tooltip)
appearance_table.Attach(language_selection_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5) appearance_table.Attach(language_selection_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5)
o.language_combo = gtk.NewComboBoxText() o.language_combo = gtk.NewComboBoxText()
o.language_combo.SetTooltipText(language_selection_tooltip) o.language_combo.SetTooltipText(language_selection_tooltip)
// Get all available languages and fill combobox. // Get all available languages and fill combobox.
lang_idx := 0 lang_idx := 0
var lang_active int = 0 var lang_active int = 0
for lang, _ := range ctx.Translator.AcceptedLanguages { for lang, _ := range ctx.Translator.AcceptedLanguages {
o.language_combo.AppendText(lang) o.language_combo.AppendText(lang)
if ctx.Translator.AcceptedLanguages[lang] == ctx.Cfg.Cfg["/general/language"] { if ctx.Translator.AcceptedLanguages[lang] == ctx.Cfg.Cfg["/general/language"] {
lang_active = lang_idx lang_active = lang_idx
} }
lang_idx += 1 lang_idx += 1
} }
o.language_combo.SetActive(lang_active) o.language_combo.SetActive(lang_active)
appearance_table.Attach(o.language_combo, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL, 5, 5) appearance_table.Attach(o.language_combo, 1, 2, 0, 1, gtk.FILL|gtk.EXPAND, gtk.FILL, 5, 5)
appearance_vbox.PackStart(appearance_table, false, true, 0) appearance_vbox.PackStart(appearance_table, false, true, 0)
o.tab_widget.AppendPage(appearance_vbox, gtk.NewLabel(ctx.Translator.Translate("Appearance", nil))) o.tab_widget.AppendPage(appearance_vbox, gtk.NewLabel(ctx.Translator.Translate("Appearance", nil)))
} }
func (o *OptionsDialog) initializeGeneralTab() { func (o *OptionsDialog) initializeGeneralTab() {
general_vbox := gtk.NewVBox(false, 0) general_vbox := gtk.NewVBox(false, 0)
general_table := gtk.NewTable(2, 2, false) general_table := gtk.NewTable(2, 2, false)
// Tray icon checkbox. // Tray icon checkbox.
show_tray_icon_label := gtk.NewLabel(ctx.Translator.Translate("Show icon in tray", nil)) show_tray_icon_label := gtk.NewLabel(ctx.Translator.Translate("Show icon in tray", nil))
show_tray_icon_label.SetAlignment(0, 0) show_tray_icon_label.SetAlignment(0, 0)
general_table.Attach(show_tray_icon_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5) general_table.Attach(show_tray_icon_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5)
o.show_tray_icon = gtk.NewCheckButtonWithLabel("") o.show_tray_icon = gtk.NewCheckButtonWithLabel("")
o.show_tray_icon.SetTooltipText(ctx.Translator.Translate("Show icon in tray", nil)) o.show_tray_icon.SetTooltipText(ctx.Translator.Translate("Show icon in tray", nil))
general_table.Attach(o.show_tray_icon, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL, 5, 5) general_table.Attach(o.show_tray_icon, 1, 2, 0, 1, gtk.FILL|gtk.EXPAND, gtk.FILL, 5, 5)
// Autoupdate checkbox. // Autoupdate checkbox.
autoupdate_tooltip := ctx.Translator.Translate("Should URTrator check for updates and update itself? Not working now.", nil) autoupdate_tooltip := ctx.Translator.Translate("Should URTrator check for updates and update itself? Not working now.", nil)
autoupdate_label := gtk.NewLabel(ctx.Translator.Translate("Automatically update URTrator?", nil)) autoupdate_label := gtk.NewLabel(ctx.Translator.Translate("Automatically update URTrator?", nil))
autoupdate_label.SetTooltipText(autoupdate_tooltip) autoupdate_label.SetTooltipText(autoupdate_tooltip)
autoupdate_label.SetAlignment(0, 0) autoupdate_label.SetAlignment(0, 0)
general_table.Attach(autoupdate_label, 0, 1, 1, 2, gtk.FILL, gtk.SHRINK, 5, 5) general_table.Attach(autoupdate_label, 0, 1, 1, 2, gtk.FILL, gtk.SHRINK, 5, 5)
o.autoupdate = gtk.NewCheckButtonWithLabel("") o.autoupdate = gtk.NewCheckButtonWithLabel("")
o.autoupdate.SetTooltipText(autoupdate_tooltip) o.autoupdate.SetTooltipText(autoupdate_tooltip)
general_table.Attach(o.autoupdate, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL, 5, 5) general_table.Attach(o.autoupdate, 1, 2, 1, 2, gtk.FILL|gtk.EXPAND, gtk.FILL, 5, 5)
// Vertical separator. // Vertical separator.
sep := gtk.NewVBox(false, 0) sep := gtk.NewVBox(false, 0)
general_vbox.PackStart(general_table, false, true, 0) general_vbox.PackStart(general_table, false, true, 0)
general_vbox.PackStart(sep, false, true, 0) general_vbox.PackStart(sep, false, true, 0)
o.tab_widget.AppendPage(general_vbox, gtk.NewLabel(ctx.Translator.Translate("General", nil))) o.tab_widget.AppendPage(general_vbox, gtk.NewLabel(ctx.Translator.Translate("General", nil)))
} }
func (o *OptionsDialog) initializeServersOptionsTab() { func (o *OptionsDialog) initializeServersOptionsTab() {
servers_options_vbox := gtk.NewVBox(false, 0) servers_options_vbox := gtk.NewVBox(false, 0)
servers_updating_table := gtk.NewTable(3, 2, false) servers_updating_table := gtk.NewTable(3, 2, false)
servers_updating_table.SetRowSpacings(2) servers_updating_table.SetRowSpacings(2)
// Master server address. // Master server address.
master_server_addr_tooltip := ctx.Translator.Translate("Address of master server. Specify in form: addr:port.", nil) master_server_addr_tooltip := ctx.Translator.Translate("Address of master server. Specify in form: addr:port.", nil)
master_server_addr_label := gtk.NewLabel(ctx.Translator.Translate("Master server address", nil)) master_server_addr_label := gtk.NewLabel(ctx.Translator.Translate("Master server address", nil))
master_server_addr_label.SetTooltipText(master_server_addr_tooltip) master_server_addr_label.SetTooltipText(master_server_addr_tooltip)
master_server_addr_label.SetAlignment(0, 0) master_server_addr_label.SetAlignment(0, 0)
servers_updating_table.Attach(master_server_addr_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5) servers_updating_table.Attach(master_server_addr_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5)
o.master_server_addr = gtk.NewEntry() o.master_server_addr = gtk.NewEntry()
o.master_server_addr.SetTooltipText(master_server_addr_tooltip) o.master_server_addr.SetTooltipText(master_server_addr_tooltip)
servers_updating_table.Attach(o.master_server_addr, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 5, 5) servers_updating_table.Attach(o.master_server_addr, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 5, 5)
// Servers autoupdate checkbox. // Servers autoupdate checkbox.
servers_autoupdate_cb_tooptip := ctx.Translator.Translate("Should servers be automatically updated?", nil) servers_autoupdate_cb_tooptip := ctx.Translator.Translate("Should servers be automatically updated?", nil)
servers_autoupdate_cb_label := gtk.NewLabel(ctx.Translator.Translate("Servers autoupdate", nil)) servers_autoupdate_cb_label := gtk.NewLabel(ctx.Translator.Translate("Servers autoupdate", nil))
servers_autoupdate_cb_label.SetTooltipText(servers_autoupdate_cb_tooptip) servers_autoupdate_cb_label.SetTooltipText(servers_autoupdate_cb_tooptip)
servers_autoupdate_cb_label.SetAlignment(0, 0) servers_autoupdate_cb_label.SetAlignment(0, 0)
servers_updating_table.Attach(servers_autoupdate_cb_label, 0, 1 ,1, 2, gtk.FILL, gtk.SHRINK, 5, 5) servers_updating_table.Attach(servers_autoupdate_cb_label, 0, 1, 1, 2, gtk.FILL, gtk.SHRINK, 5, 5)
o.servers_autoupdate = gtk.NewCheckButtonWithLabel("") o.servers_autoupdate = gtk.NewCheckButtonWithLabel("")
o.servers_autoupdate.SetTooltipText(servers_autoupdate_cb_tooptip) o.servers_autoupdate.SetTooltipText(servers_autoupdate_cb_tooptip)
servers_updating_table.Attach(o.servers_autoupdate, 1, 2, 1, 2, gtk.EXPAND | gtk.FILL, gtk.FILL, 5, 5) servers_updating_table.Attach(o.servers_autoupdate, 1, 2, 1, 2, gtk.EXPAND|gtk.FILL, gtk.FILL, 5, 5)
// Servers update timeout. // Servers update timeout.
servers_autoupdate_timeout_tooltip := ctx.Translator.Translate("Timeout which will trigger servers information update, in minutes.", nil) servers_autoupdate_timeout_tooltip := ctx.Translator.Translate("Timeout which will trigger servers information update, in minutes.", nil)
servers_autoupdate_label := gtk.NewLabel(ctx.Translator.Translate("Servers update timeout (minutes)", nil)) servers_autoupdate_label := gtk.NewLabel(ctx.Translator.Translate("Servers update timeout (minutes)", nil))
servers_autoupdate_label.SetTooltipText(servers_autoupdate_timeout_tooltip) servers_autoupdate_label.SetTooltipText(servers_autoupdate_timeout_tooltip)
servers_autoupdate_label.SetAlignment(0, 0) servers_autoupdate_label.SetAlignment(0, 0)
servers_updating_table.Attach(servers_autoupdate_label, 0, 1, 2, 3, gtk.FILL, gtk.SHRINK, 5, 5) servers_updating_table.Attach(servers_autoupdate_label, 0, 1, 2, 3, gtk.FILL, gtk.SHRINK, 5, 5)
o.servers_autoupdate_timeout = gtk.NewEntry() o.servers_autoupdate_timeout = gtk.NewEntry()
o.servers_autoupdate_timeout.SetTooltipText(servers_autoupdate_timeout_tooltip) o.servers_autoupdate_timeout.SetTooltipText(servers_autoupdate_timeout_tooltip)
servers_updating_table.Attach(o.servers_autoupdate_timeout, 1, 2, 2, 3, gtk.FILL, gtk.FILL, 5, 5) servers_updating_table.Attach(o.servers_autoupdate_timeout, 1, 2, 2, 3, gtk.FILL, gtk.FILL, 5, 5)
// Vertical separator. // Vertical separator.
sep := gtk.NewVBox(false, 0) sep := gtk.NewVBox(false, 0)
servers_options_vbox.PackStart(servers_updating_table, false, true, 0) servers_options_vbox.PackStart(servers_updating_table, false, true, 0)
servers_options_vbox.PackStart(sep, true, true, 0) servers_options_vbox.PackStart(sep, true, true, 0)
o.tab_widget.AppendPage(servers_options_vbox, gtk.NewLabel(ctx.Translator.Translate("Servers updating", nil))) o.tab_widget.AppendPage(servers_options_vbox, gtk.NewLabel(ctx.Translator.Translate("Servers updating", nil)))
} }
func (o *OptionsDialog) initializeStorages() { func (o *OptionsDialog) initializeStorages() {
// Structure: // Structure:
// Name|Version|Second X session // Name|Version|Second X session
o.profiles_list_store = gtk.NewListStore(glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_BOOL) o.profiles_list_store = gtk.NewListStore(glib.G_TYPE_STRING, glib.G_TYPE_STRING, glib.G_TYPE_BOOL)
} }
func (o *OptionsDialog) initializeTabs() { func (o *OptionsDialog) initializeTabs() {
o.initializeStorages() o.initializeStorages()
o.tab_widget = gtk.NewNotebook() o.tab_widget = gtk.NewNotebook()
o.tab_widget.SetTabPos(gtk.POS_LEFT) o.tab_widget.SetTabPos(gtk.POS_LEFT)
o.initializeGeneralTab() o.initializeGeneralTab()
o.initializeAppearanceTab() o.initializeAppearanceTab()
o.initializeUrtTab() o.initializeUrtTab()
o.initializeServersOptionsTab() o.initializeServersOptionsTab()
// Buttons for saving and discarding changes. // Buttons for saving and discarding changes.
buttons_hbox := gtk.NewHBox(false, 0) buttons_hbox := gtk.NewHBox(false, 0)
sep := gtk.NewHBox(false, 0) sep := gtk.NewHBox(false, 0)
cancel_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("Cancel", nil)) cancel_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("Cancel", nil))
cancel_button.Clicked(o.closeOptionsDialogByCancel) cancel_button.Clicked(o.closeOptionsDialogByCancel)
ok_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("OK", nil)) ok_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("OK", nil))
ok_button.Clicked(o.closeOptionsDialogWithSaving) ok_button.Clicked(o.closeOptionsDialogWithSaving)
buttons_hbox.PackStart(sep, true, true, 5) buttons_hbox.PackStart(sep, true, true, 5)
buttons_hbox.PackStart(cancel_button, false, true, 5) buttons_hbox.PackStart(cancel_button, false, true, 5)
buttons_hbox.PackStart(ok_button, false, true, 5) buttons_hbox.PackStart(ok_button, false, true, 5)
o.vbox.PackStart(o.tab_widget, true, true, 5) o.vbox.PackStart(o.tab_widget, true, true, 5)
o.vbox.PackStart(buttons_hbox, false, true, 5) o.vbox.PackStart(buttons_hbox, false, true, 5)
ctx.Eventer.AddEventHandler("loadProfilesIntoOptionsWindow", o.loadProfiles) ctx.Eventer.AddEventHandler("loadProfilesIntoOptionsWindow", o.loadProfiles)
} }
func (o *OptionsDialog) initializeUrtTab() { func (o *OptionsDialog) initializeUrtTab() {
urt_hbox := gtk.NewHBox(false, 5) urt_hbox := gtk.NewHBox(false, 5)
// Profiles list. // Profiles list.
o.profiles_list = gtk.NewTreeView() o.profiles_list = gtk.NewTreeView()
o.profiles_list.SetTooltipText(ctx.Translator.Translate("All available profiles", nil)) o.profiles_list.SetTooltipText(ctx.Translator.Translate("All available profiles", nil))
urt_hbox.Add(o.profiles_list) urt_hbox.Add(o.profiles_list)
o.profiles_list.SetModel(o.profiles_list_store) o.profiles_list.SetModel(o.profiles_list_store)
o.profiles_list.AppendColumn(gtk.NewTreeViewColumnWithAttributes(ctx.Translator.Translate("Profile name", nil), gtk.NewCellRendererText(), "text", 0)) o.profiles_list.AppendColumn(gtk.NewTreeViewColumnWithAttributes(ctx.Translator.Translate("Profile name", nil), gtk.NewCellRendererText(), "text", 0))
o.profiles_list.AppendColumn(gtk.NewTreeViewColumnWithAttributes(ctx.Translator.Translate("Urban Terror version", nil), gtk.NewCellRendererText(), "text", 1)) o.profiles_list.AppendColumn(gtk.NewTreeViewColumnWithAttributes(ctx.Translator.Translate("Urban Terror version", nil), gtk.NewCellRendererText(), "text", 1))
// Profiles list buttons. // Profiles list buttons.
urt_profiles_buttons_vbox := gtk.NewVBox(false, 0) urt_profiles_buttons_vbox := gtk.NewVBox(false, 0)
button_add := gtk.NewButtonWithLabel(ctx.Translator.Translate("Add", nil)) button_add := gtk.NewButtonWithLabel(ctx.Translator.Translate("Add", nil))
button_add.SetTooltipText(ctx.Translator.Translate("Add new profile", nil)) button_add.SetTooltipText(ctx.Translator.Translate("Add new profile", nil))
button_add.Clicked(o.addProfile) button_add.Clicked(o.addProfile)
urt_profiles_buttons_vbox.PackStart(button_add, false, true, 0) urt_profiles_buttons_vbox.PackStart(button_add, false, true, 0)
button_edit := gtk.NewButtonWithLabel(ctx.Translator.Translate("Edit", nil)) button_edit := gtk.NewButtonWithLabel(ctx.Translator.Translate("Edit", nil))
button_edit.SetTooltipText(ctx.Translator.Translate("Edit selected profile. Do nothing if no profile was selected.", nil)) button_edit.SetTooltipText(ctx.Translator.Translate("Edit selected profile. Do nothing if no profile was selected.", nil))
button_edit.Clicked(o.editProfile) button_edit.Clicked(o.editProfile)
urt_profiles_buttons_vbox.PackStart(button_edit, false, true, 5) urt_profiles_buttons_vbox.PackStart(button_edit, false, true, 5)
// Spacer for profiles list buttons. // Spacer for profiles list buttons.
sep := gtk.NewVBox(false, 0) sep := gtk.NewVBox(false, 0)
urt_profiles_buttons_vbox.PackStart(sep, true, true, 5) urt_profiles_buttons_vbox.PackStart(sep, true, true, 5)
button_delete := gtk.NewButtonWithLabel(ctx.Translator.Translate("Delete", nil)) button_delete := gtk.NewButtonWithLabel(ctx.Translator.Translate("Delete", nil))
button_delete.SetTooltipText(ctx.Translator.Translate("Delete selected profile. Do nothing if no profile was selected.", nil)) button_delete.SetTooltipText(ctx.Translator.Translate("Delete selected profile. Do nothing if no profile was selected.", nil))
button_delete.Clicked(o.deleteProfile) button_delete.Clicked(o.deleteProfile)
urt_profiles_buttons_vbox.PackStart(button_delete, false, true, 0) urt_profiles_buttons_vbox.PackStart(button_delete, false, true, 0)
urt_hbox.Add(urt_profiles_buttons_vbox) urt_hbox.Add(urt_profiles_buttons_vbox)
o.tab_widget.AppendPage(urt_hbox, gtk.NewLabel(ctx.Translator.Translate("Urban Terror", nil))) o.tab_widget.AppendPage(urt_hbox, gtk.NewLabel(ctx.Translator.Translate("Urban Terror", nil)))
// Load Profiles. // Load Profiles.
ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{}) ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{})
} }
func (o *OptionsDialog) loadProfiles(data map[string]string) { func (o *OptionsDialog) loadProfiles(data map[string]string) {
fmt.Println("Loading profiles...") fmt.Println("Loading profiles...")
o.profiles_list_store.Clear() o.profiles_list_store.Clear()
ctx.Cache.ProfilesMutex.Lock() ctx.Cache.ProfilesMutex.Lock()
for _, p := range ctx.Cache.Profiles { for _, p := range ctx.Cache.Profiles {
var iter gtk.TreeIter var iter gtk.TreeIter
o.profiles_list_store.Append(&iter) o.profiles_list_store.Append(&iter)
o.profiles_list_store.Set(&iter, 0, p.Profile.Name) o.profiles_list_store.Set(&iter, 0, p.Profile.Name)
o.profiles_list_store.Set(&iter, 1, p.Profile.Version) o.profiles_list_store.Set(&iter, 1, p.Profile.Version)
} }
ctx.Cache.ProfilesMutex.Unlock() ctx.Cache.ProfilesMutex.Unlock()
} }
func (o *OptionsDialog) saveAppearance() { func (o *OptionsDialog) saveAppearance() {
ctx.Cfg.Cfg["/general/language"] = ctx.Translator.AcceptedLanguages[o.language_combo.GetActiveText()] ctx.Cfg.Cfg["/general/language"] = ctx.Translator.AcceptedLanguages[o.language_combo.GetActiveText()]
} }
func (o *OptionsDialog) saveGeneral() { func (o *OptionsDialog) saveGeneral() {
if o.show_tray_icon.GetActive() { if o.show_tray_icon.GetActive() {
ctx.Cfg.Cfg["/general/show_tray_icon"] = "1" ctx.Cfg.Cfg["/general/show_tray_icon"] = "1"
} else { } else {
ctx.Cfg.Cfg["/general/show_tray_icon"] = "0" ctx.Cfg.Cfg["/general/show_tray_icon"] = "0"
} }
if o.autoupdate.GetActive() { if o.autoupdate.GetActive() {
ctx.Cfg.Cfg["/general/urtrator_autoupdate"] = "1" ctx.Cfg.Cfg["/general/urtrator_autoupdate"] = "1"
} else { } else {
ctx.Cfg.Cfg["/general/urtrator_autoupdate"] = "0" ctx.Cfg.Cfg["/general/urtrator_autoupdate"] = "0"
} }
// Servers updating tab. // Servers updating tab.
master_server_addr := o.master_server_addr.GetText() master_server_addr := o.master_server_addr.GetText()
if len(master_server_addr) < 1 { if len(master_server_addr) < 1 {
ctx.Cfg.Cfg["/servers_updating/master_server"] = "master.urbanterror.info:27900" ctx.Cfg.Cfg["/servers_updating/master_server"] = "master.urbanterror.info:27900"
} else { } else {
ctx.Cfg.Cfg["/servers_updating/master_server"] = master_server_addr ctx.Cfg.Cfg["/servers_updating/master_server"] = master_server_addr
} }
if o.servers_autoupdate.GetActive() { if o.servers_autoupdate.GetActive() {
ctx.Cfg.Cfg["/servers_updating/servers_autoupdate"] = "1" ctx.Cfg.Cfg["/servers_updating/servers_autoupdate"] = "1"
} else { } else {
ctx.Cfg.Cfg["/servers_updating/servers_autoupdate"] = "0" ctx.Cfg.Cfg["/servers_updating/servers_autoupdate"] = "0"
} }
update_timeout := o.servers_autoupdate_timeout.GetText() update_timeout := o.servers_autoupdate_timeout.GetText()
if len(update_timeout) < 1 { if len(update_timeout) < 1 {
ctx.Cfg.Cfg["/servers_updating/servers_autoupdate_timeout"] = "10" ctx.Cfg.Cfg["/servers_updating/servers_autoupdate_timeout"] = "10"
} else { } else {
ctx.Cfg.Cfg["/servers_updating/servers_autoupdate_timeout"] = update_timeout ctx.Cfg.Cfg["/servers_updating/servers_autoupdate_timeout"] = update_timeout
} }
ctx.Eventer.LaunchEvent("initializeTasksForMainWindow", map[string]string{}) ctx.Eventer.LaunchEvent("initializeTasksForMainWindow", map[string]string{})
} }
func (o *OptionsDialog) ShowOptionsDialog() { func (o *OptionsDialog) ShowOptionsDialog() {
o.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL) o.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
o.window.SetTitle(ctx.Translator.Translate("URTrator - Options", nil)) o.window.SetTitle(ctx.Translator.Translate("URTrator - Options", nil))
o.window.Connect("destroy", o.closeOptionsDialogWithDiscard) o.window.Connect("destroy", o.closeOptionsDialogWithDiscard)
o.window.SetModal(true) o.window.SetModal(true)
o.window.SetSizeRequest(750, 600) o.window.SetSizeRequest(750, 600)
o.window.SetPosition(gtk.WIN_POS_CENTER) o.window.SetPosition(gtk.WIN_POS_CENTER)
o.window.SetIcon(logo) o.window.SetIcon(logo)
o.vbox = gtk.NewVBox(false, 0) o.vbox = gtk.NewVBox(false, 0)
o.initializeTabs() o.initializeTabs()
o.fill() o.fill()
o.window.Add(o.vbox) o.window.Add(o.vbox)
ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{}) ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{})
o.window.ShowAll() o.window.ShowAll()
} }

View File

@ -10,391 +10,390 @@
package ui package ui
import ( import (
// stdlib // stdlib
"fmt" "fmt"
"os" "os"
"runtime" "runtime"
"strings" "strings"
// Local // Local
"github.com/pztrn/urtrator/datamodels" "gitlab.com/pztrn/urtrator/datamodels"
// Other // Other
"github.com/mattn/go-gtk/gtk" "github.com/mattn/go-gtk/gtk"
//"github.com/mattn/go-gtk/glib" //"github.com/mattn/go-gtk/glib"
) )
type OptionsProfile struct { type OptionsProfile struct {
// Window. // Window.
window *gtk.Window window *gtk.Window
// Main table. // Main table.
table *gtk.Table table *gtk.Table
// Profile name. // Profile name.
profile_name *gtk.Entry profile_name *gtk.Entry
// Binary path. // Binary path.
binary_path *gtk.Entry binary_path *gtk.Entry
// Profile directory path. // Profile directory path.
profile_path *gtk.Entry profile_path *gtk.Entry
// Urban Terror versions combobox // Urban Terror versions combobox
urt_version_combo *gtk.ComboBoxText urt_version_combo *gtk.ComboBoxText
// Another X session? // Another X session?
another_x_session *gtk.CheckButton another_x_session *gtk.CheckButton
// Additional parameters for game launching. // Additional parameters for game launching.
additional_parameters *gtk.Entry additional_parameters *gtk.Entry
// File chooser dialog for selecting binary. // File chooser dialog for selecting binary.
f *gtk.FileChooserDialog f *gtk.FileChooserDialog
// Profile directory chooser dialog. // Profile directory chooser dialog.
p *gtk.FileChooserDialog p *gtk.FileChooserDialog
// Flags. // Flags.
// This is profile update? // This is profile update?
update bool update bool
// Others. // Others.
// Old profile, needed for proper update. // Old profile, needed for proper update.
old_profile *datamodels.Profile old_profile *datamodels.Profile
} }
func (op *OptionsProfile) browseForBinary() { func (op *OptionsProfile) browseForBinary() {
op.f = gtk.NewFileChooserDialog(ctx.Translator.Translate("URTrator - Select Urban Terror binary", nil), op.window, gtk.FILE_CHOOSER_ACTION_OPEN, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) op.f = gtk.NewFileChooserDialog(ctx.Translator.Translate("URTrator - Select Urban Terror binary", nil), op.window, gtk.FILE_CHOOSER_ACTION_OPEN, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
op.f.Response(op.browseForBinaryHelper) op.f.Response(op.browseForBinaryHelper)
op.f.Run() op.f.Run()
} }
func (op *OptionsProfile) browseForProfile() { func (op *OptionsProfile) browseForProfile() {
op.p = gtk.NewFileChooserDialog(ctx.Translator.Translate("URTrator - Select Urban Terror profile path", nil), op.window, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) op.p = gtk.NewFileChooserDialog(ctx.Translator.Translate("URTrator - Select Urban Terror profile path", nil), op.window, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
op.p.Response(op.browseForProfileHelper) op.p.Response(op.browseForProfileHelper)
if op.profile_path.GetText() != "" { if op.profile_path.GetText() != "" {
op.p.SetCurrentFolder(op.profile_path.GetText()) op.p.SetCurrentFolder(op.profile_path.GetText())
} }
op.p.Run() op.p.Run()
} }
func (op *OptionsProfile) browseForBinaryHelper() { func (op *OptionsProfile) browseForBinaryHelper() {
filename := op.f.GetFilename() filename := op.f.GetFilename()
op.binary_path.SetText(filename) op.binary_path.SetText(filename)
op.f.Destroy() op.f.Destroy()
fmt.Println(filename) fmt.Println(filename)
// Check for valid filename. // Check for valid filename.
// ToDo: add more OSes. // ToDo: add more OSes.
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
// Filename should end with approriate arch. // Filename should end with approriate arch.
if runtime.GOARCH == "amd64" { if runtime.GOARCH == "amd64" {
if len(filename) > 0 && strings.Split(filename, ".")[1] != "x86_64" && strings.Split(filename, ".")[0] != "Quake3-UrT" { if len(filename) > 0 && strings.Split(filename, ".")[1] != "x86_64" && strings.Split(filename, ".")[0] != "Quake3-UrT" {
fmt.Println("Invalid binary selected!") fmt.Println("Invalid binary selected!")
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("Invalid binary selected!\nAccording to your OS, it should be", nil) + " Quake3-UrT.x86_64." mbox_string := ctx.Translator.Translate("Invalid binary selected!\nAccording to your OS, it should be", nil) + " Quake3-UrT.x86_64."
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() { m.Response(func() {
m.Destroy() m.Destroy()
}) })
m.Run() m.Run()
} else { } else {
// //
} }
op.binary_path.SetText("") op.binary_path.SetText("")
} }
} }
} else if runtime.GOOS == "darwin" { } else if runtime.GOOS == "darwin" {
// Official application: Quake3-UrT.app. Split by it and get second // Official application: Quake3-UrT.app. Split by it and get second
// part of string. // part of string.
if strings.Contains(filename, "Quake3-UrT.app") { if strings.Contains(filename, "Quake3-UrT.app") {
filename = strings.Split(filename, "Quake3-UrT.app")[1] filename = strings.Split(filename, "Quake3-UrT.app")[1]
if len(filename) > 0 && !strings.Contains(strings.Split(filename, ".")[1], "x86_64") && !strings.Contains(strings.Split(filename, ".")[0], "Quake3-UrT") { if len(filename) > 0 && !strings.Contains(strings.Split(filename, ".")[1], "x86_64") && !strings.Contains(strings.Split(filename, ".")[0], "Quake3-UrT") {
fmt.Println("Invalid binary selected!") fmt.Println("Invalid binary selected!")
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("Invalid binary selected!\nAccording to your OS, it should be", nil) + " Quake3-UrT.app/Contents/MacOS/Quake3-UrT.x86_64." mbox_string := ctx.Translator.Translate("Invalid binary selected!\nAccording to your OS, it should be", nil) + " Quake3-UrT.app/Contents/MacOS/Quake3-UrT.x86_64."
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() { m.Response(func() {
m.Destroy() m.Destroy()
}) })
m.Run() m.Run()
} else { } else {
// //
} }
op.binary_path.SetText("") op.binary_path.SetText("")
} }
} else { } else {
// Temporary disable all these modals on Linux. // Temporary disable all these modals on Linux.
// See https://github.com/mattn/go-gtk/issues/289. // See https://github.com/mattn/go-gtk/issues/289.
if runtime.GOOS != "linux" { if runtime.GOOS != "linux" {
mbox_string := ctx.Translator.Translate("Invalid binary selected!\nAccording to your OS, it should be", nil) + " Quake3-UrT.app/Contents/MacOS/Quake3-UrT.x86_64.\n\n" + ctx.Translator.Translate("Note, that currently URTrator supports only official binary.", nil) mbox_string := ctx.Translator.Translate("Invalid binary selected!\nAccording to your OS, it should be", nil) + " Quake3-UrT.app/Contents/MacOS/Quake3-UrT.x86_64.\n\n" + ctx.Translator.Translate("Note, that currently URTrator supports only official binary.", nil)
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() { m.Response(func() {
m.Destroy() m.Destroy()
}) })
m.Run() m.Run()
} else { } else {
// //
} }
} }
} }
if op.profile_path.GetText() == "" { if op.profile_path.GetText() == "" {
op.profile_path.SetText(ctx.Cfg.TEMP["DEFAULT_PROFILE_PATH"]) op.profile_path.SetText(ctx.Cfg.TEMP["DEFAULT_PROFILE_PATH"])
} }
} }
func (op *OptionsProfile) browseForProfileHelper() { func (op *OptionsProfile) browseForProfileHelper() {
directory := op.p.GetFilename() directory := op.p.GetFilename()
op.profile_path.SetText(directory) op.profile_path.SetText(directory)
op.p.Destroy() op.p.Destroy()
} }
func (op *OptionsProfile) closeByCancel() { func (op *OptionsProfile) closeByCancel() {
op.window.Destroy() op.window.Destroy()
} }
func (op *OptionsProfile) closeWithDiscard() { func (op *OptionsProfile) closeWithDiscard() {
} }
func (op *OptionsProfile) Initialize(update bool) { func (op *OptionsProfile) Initialize(update bool) {
if update { if update {
op.update = true op.update = true
} }
op.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL) op.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
if update { if update {
op.window.SetTitle(ctx.Translator.Translate("URTrator - Update Urban Terror profile", nil)) op.window.SetTitle(ctx.Translator.Translate("URTrator - Update Urban Terror profile", nil))
} else { } else {
op.window.SetTitle(ctx.Translator.Translate("URTrator - Add Urban Terror profile", nil)) op.window.SetTitle(ctx.Translator.Translate("URTrator - Add Urban Terror profile", nil))
} }
op.window.Connect("destroy", op.closeWithDiscard) op.window.Connect("destroy", op.closeWithDiscard)
op.window.SetModal(true) op.window.SetModal(true)
op.window.SetSizeRequest(550, 400) op.window.SetSizeRequest(550, 400)
op.window.SetPosition(gtk.WIN_POS_CENTER) op.window.SetPosition(gtk.WIN_POS_CENTER)
op.window.SetIcon(logo) op.window.SetIcon(logo)
op.table = gtk.NewTable(7, 2, false) op.table = gtk.NewTable(7, 2, false)
op.table.SetRowSpacings(2) op.table.SetRowSpacings(2)
// Profile name. // Profile name.
profile_name_tooltip := ctx.Translator.Translate("This how you will see profile on profiles lists.", nil) profile_name_tooltip := ctx.Translator.Translate("This how you will see profile on profiles lists.", nil)
pn_label := gtk.NewLabel(ctx.Translator.Translate("Profile name:", nil)) pn_label := gtk.NewLabel(ctx.Translator.Translate("Profile name:", nil))
pn_label.SetTooltipText(profile_name_tooltip) pn_label.SetTooltipText(profile_name_tooltip)
pn_label.SetAlignment(0, 0) pn_label.SetAlignment(0, 0)
op.table.Attach(pn_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5) op.table.Attach(pn_label, 0, 1, 0, 1, gtk.FILL, gtk.SHRINK, 5, 5)
op.profile_name = gtk.NewEntry() op.profile_name = gtk.NewEntry()
op.profile_name.SetTooltipText(profile_name_tooltip) op.profile_name.SetTooltipText(profile_name_tooltip)
op.table.Attach(op.profile_name, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 5, 5) op.table.Attach(op.profile_name, 1, 2, 0, 1, gtk.FILL, gtk.FILL, 5, 5)
// Urban Terror version.
urt_version_tooltip := ctx.Translator.Translate("Urban Terror version for which this profile applies.", nil)
urt_version_label := gtk.NewLabel(ctx.Translator.Translate("Urban Terror version:", nil))
urt_version_label.SetTooltipText(urt_version_tooltip)
urt_version_label.SetAlignment(0, 0)
op.table.Attach(urt_version_label, 0, 1, 1, 2, gtk.FILL, gtk.SHRINK, 5, 5)
// Urban Terror version. op.urt_version_combo = gtk.NewComboBoxText()
urt_version_tooltip := ctx.Translator.Translate("Urban Terror version for which this profile applies.", nil) op.urt_version_combo.SetTooltipText(urt_version_tooltip)
urt_version_label := gtk.NewLabel(ctx.Translator.Translate("Urban Terror version:", nil)) op.urt_version_combo.AppendText("4.2.023")
urt_version_label.SetTooltipText(urt_version_tooltip) op.urt_version_combo.AppendText("4.3.1")
urt_version_label.SetAlignment(0, 0) op.urt_version_combo.AppendText("4.3.2")
op.table.Attach(urt_version_label, 0, 1, 1, 2, gtk.FILL, gtk.SHRINK, 5, 5) op.urt_version_combo.SetActive(2)
op.table.Attach(op.urt_version_combo, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5)
op.urt_version_combo = gtk.NewComboBoxText() // Urban Terror binary path.
op.urt_version_combo.SetTooltipText(urt_version_tooltip) select_binary_tooltip := ctx.Translator.Translate("Urban Terror binary. Some checks will be executed, so make sure you have selected right binary:\n\nQuake3-UrT.i386 for linux-x86\nQuake3-UrT.x86_64 for linux-amd64\nQuake3-UrT.app for macOS", nil)
op.urt_version_combo.AppendText("4.2.023") binpath_hbox := gtk.NewHBox(false, 0)
op.urt_version_combo.AppendText("4.3.1") binpath_label := gtk.NewLabel(ctx.Translator.Translate("Urban Terror binary:", nil))
op.urt_version_combo.AppendText("4.3.2") binpath_label.SetTooltipText(select_binary_tooltip)
op.urt_version_combo.SetActive(2) binpath_label.SetAlignment(0, 0)
op.table.Attach(op.urt_version_combo, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 5, 5) op.table.Attach(binpath_label, 0, 1, 2, 3, gtk.FILL, gtk.SHRINK, 5, 5)
// Urban Terror binary path. op.binary_path = gtk.NewEntry()
select_binary_tooltip := ctx.Translator.Translate("Urban Terror binary. Some checks will be executed, so make sure you have selected right binary:\n\nQuake3-UrT.i386 for linux-x86\nQuake3-UrT.x86_64 for linux-amd64\nQuake3-UrT.app for macOS", nil) op.binary_path.SetTooltipText(select_binary_tooltip)
binpath_hbox := gtk.NewHBox(false, 0) button_select_binary := gtk.NewButtonWithLabel(ctx.Translator.Translate("Browse", nil))
binpath_label := gtk.NewLabel(ctx.Translator.Translate("Urban Terror binary:", nil)) button_select_binary.SetTooltipText(select_binary_tooltip)
binpath_label.SetTooltipText(select_binary_tooltip) button_select_binary.Clicked(op.browseForBinary)
binpath_label.SetAlignment(0, 0) binpath_hbox.PackStart(op.binary_path, true, true, 5)
op.table.Attach(binpath_label, 0, 1, 2, 3, gtk.FILL, gtk.SHRINK, 5, 5) binpath_hbox.PackStart(button_select_binary, false, true, 5)
op.table.Attach(binpath_hbox, 1, 2, 2, 3, gtk.FILL, gtk.FILL, 0, 0)
op.binary_path = gtk.NewEntry() // Path to Urban Terror's profile directory.
op.binary_path.SetTooltipText(select_binary_tooltip) // Should be in user's home directory automatically, but can be
button_select_binary := gtk.NewButtonWithLabel(ctx.Translator.Translate("Browse", nil)) // changed :).
button_select_binary.SetTooltipText(select_binary_tooltip) select_profile_path_tooltip := ctx.Translator.Translate("Urban Terror profile path.\n\nSpecify directory where configs, demos\nand downloaded maps are located.\n\nDefault: $HOME/.q3ut4", nil)
button_select_binary.Clicked(op.browseForBinary) profile_path_hbox := gtk.NewHBox(false, 0)
binpath_hbox.PackStart(op.binary_path, true, true, 5) profile_path_label := gtk.NewLabel(ctx.Translator.Translate("Profile path:", nil))
binpath_hbox.PackStart(button_select_binary, false, true, 5) profile_path_label.SetTooltipText(select_profile_path_tooltip)
op.table.Attach(binpath_hbox, 1, 2, 2, 3, gtk.FILL, gtk.FILL, 0, 0) profile_path_label.SetAlignment(0, 0)
op.table.Attach(profile_path_label, 0, 1, 3, 4, gtk.FILL, gtk.SHRINK, 5, 5)
// Path to Urban Terror's profile directory. op.profile_path = gtk.NewEntry()
// Should be in user's home directory automatically, but can be op.profile_path.SetTooltipText(select_profile_path_tooltip)
// changed :). button_select_path := gtk.NewButtonWithLabel(ctx.Translator.Translate("Browse", nil))
select_profile_path_tooltip := ctx.Translator.Translate("Urban Terror profile path.\n\nSpecify directory where configs, demos\nand downloaded maps are located.\n\nDefault: $HOME/.q3ut4", nil) button_select_path.SetTooltipText(select_profile_path_tooltip)
profile_path_hbox := gtk.NewHBox(false, 0) button_select_path.Clicked(op.browseForProfile)
profile_path_label := gtk.NewLabel(ctx.Translator.Translate("Profile path:", nil)) profile_path_hbox.PackStart(op.profile_path, true, true, 5)
profile_path_label.SetTooltipText(select_profile_path_tooltip) profile_path_hbox.PackStart(button_select_path, false, true, 5)
profile_path_label.SetAlignment(0, 0) op.table.Attach(profile_path_hbox, 1, 2, 3, 4, gtk.FILL, gtk.FILL, 0, 0)
op.table.Attach(profile_path_label, 0, 1, 3, 4, gtk.FILL, gtk.SHRINK, 5, 5)
op.profile_path = gtk.NewEntry() // Should we use additional X session?
op.profile_path.SetTooltipText(select_profile_path_tooltip) another_x_tooltip := ctx.Translator.Translate("If this is checked, Urban Terror will be launched in another X session.\n\nThis could help if you're experiencing visual lag, glitches and FPS drops under compositing WMs, like Mutter and KWin.", nil)
button_select_path := gtk.NewButtonWithLabel(ctx.Translator.Translate("Browse", nil)) another_x_label := gtk.NewLabel(ctx.Translator.Translate("Start Urban Terror in another X session?", nil))
button_select_path.SetTooltipText(select_profile_path_tooltip) another_x_label.SetTooltipText(another_x_tooltip)
button_select_path.Clicked(op.browseForProfile) another_x_label.SetAlignment(0, 0)
profile_path_hbox.PackStart(op.profile_path, true, true, 5) op.table.Attach(another_x_label, 0, 1, 4, 5, gtk.FILL, gtk.SHRINK, 5, 5)
profile_path_hbox.PackStart(button_select_path, false, true, 5) op.another_x_session = gtk.NewCheckButtonWithLabel("")
op.table.Attach(profile_path_hbox, 1, 2, 3, 4, gtk.FILL, gtk.FILL, 0, 0) op.another_x_session.SetTooltipText(another_x_tooltip)
// macOS and Windows can't do that :).
if runtime.GOOS != "linux" {
op.another_x_session.SetSensitive(false)
}
op.table.Attach(op.another_x_session, 1, 2, 4, 5, gtk.FILL, gtk.FILL, 5, 5)
// Should we use additional X session? // Additional game parameters.
another_x_tooltip := ctx.Translator.Translate("If this is checked, Urban Terror will be launched in another X session.\n\nThis could help if you're experiencing visual lag, glitches and FPS drops under compositing WMs, like Mutter and KWin.", nil) params_tooltip := ctx.Translator.Translate("Additional parameters that will be passed to Urban Terror executable.", nil)
another_x_label := gtk.NewLabel(ctx.Translator.Translate("Start Urban Terror in another X session?", nil)) params_label := gtk.NewLabel(ctx.Translator.Translate("Additional parameters:", nil))
another_x_label.SetTooltipText(another_x_tooltip) params_label.SetTooltipText(params_tooltip)
another_x_label.SetAlignment(0, 0) params_label.SetAlignment(0, 0)
op.table.Attach(another_x_label, 0, 1, 4, 5, gtk.FILL, gtk.SHRINK, 5, 5) op.table.Attach(params_label, 0, 1, 5, 6, gtk.FILL, gtk.SHRINK, 5, 5)
op.another_x_session = gtk.NewCheckButtonWithLabel("")
op.another_x_session.SetTooltipText(another_x_tooltip)
// macOS and Windows can't do that :).
if runtime.GOOS != "linux" {
op.another_x_session.SetSensitive(false)
}
op.table.Attach(op.another_x_session, 1, 2, 4, 5, gtk.FILL, gtk.FILL, 5, 5)
// Additional game parameters. op.additional_parameters = gtk.NewEntry()
params_tooltip := ctx.Translator.Translate("Additional parameters that will be passed to Urban Terror executable.", nil) op.additional_parameters.SetTooltipText(params_tooltip)
params_label := gtk.NewLabel(ctx.Translator.Translate("Additional parameters:", nil)) op.table.Attach(op.additional_parameters, 1, 2, 5, 6, gtk.FILL, gtk.FILL, 5, 5)
params_label.SetTooltipText(params_tooltip)
params_label.SetAlignment(0, 0)
op.table.Attach(params_label, 0, 1, 5, 6, gtk.FILL, gtk.SHRINK, 5, 5)
op.additional_parameters = gtk.NewEntry() // Invisible thing.
op.additional_parameters.SetTooltipText(params_tooltip) inv_label := gtk.NewLabel("")
op.table.Attach(op.additional_parameters, 1, 2, 5, 6, gtk.FILL, gtk.FILL, 5, 5) op.table.Attach(inv_label, 1, 2, 6, 7, gtk.EXPAND, gtk.FILL, 5, 5)
// Invisible thing. // The buttons.
inv_label := gtk.NewLabel("") buttons_box := gtk.NewHBox(false, 0)
op.table.Attach(inv_label, 1, 2, 6, 7, gtk.EXPAND, gtk.FILL, 5, 5) buttons_sep := gtk.NewHBox(false, 0)
// The buttons. cancel_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("Cancel", nil))
buttons_box := gtk.NewHBox(false, 0) cancel_button.SetTooltipText(ctx.Translator.Translate("Close without saving", nil))
buttons_sep := gtk.NewHBox(false, 0) cancel_button.Clicked(op.closeByCancel)
buttons_box.PackStart(cancel_button, false, true, 5)
cancel_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("Cancel", nil)) buttons_box.PackStart(buttons_sep, true, true, 5)
cancel_button.SetTooltipText(ctx.Translator.Translate("Close without saving", nil))
cancel_button.Clicked(op.closeByCancel)
buttons_box.PackStart(cancel_button, false, true, 5)
buttons_box.PackStart(buttons_sep, true, true, 5) add_button := gtk.NewButton()
if op.update {
add_button.SetLabel(ctx.Translator.Translate("Update", nil))
add_button.SetTooltipText(ctx.Translator.Translate("Update profile", nil))
} else {
add_button.SetLabel(ctx.Translator.Translate("Add", nil))
add_button.SetTooltipText(ctx.Translator.Translate("Add profile", nil))
}
add_button.Clicked(op.saveProfile)
buttons_box.PackStart(add_button, false, true, 5)
add_button := gtk.NewButton() vert_sep_box := gtk.NewVBox(false, 0)
if op.update {
add_button.SetLabel(ctx.Translator.Translate("Update", nil))
add_button.SetTooltipText(ctx.Translator.Translate("Update profile", nil))
} else {
add_button.SetLabel(ctx.Translator.Translate("Add", nil))
add_button.SetTooltipText(ctx.Translator.Translate("Add profile", nil))
}
add_button.Clicked(op.saveProfile)
buttons_box.PackStart(add_button, false, true, 5)
vert_sep_box := gtk.NewVBox(false, 0) vbox := gtk.NewVBox(false, 0)
vbox.PackStart(op.table, false, true, 5)
vbox.PackStart(vert_sep_box, true, true, 5)
vbox.PackStart(buttons_box, false, true, 5)
vbox := gtk.NewVBox(false, 0) op.window.Add(vbox)
vbox.PackStart(op.table, false, true, 5) op.window.ShowAll()
vbox.PackStart(vert_sep_box, true, true, 5)
vbox.PackStart(buttons_box, false, true, 5)
op.window.Add(vbox)
op.window.ShowAll()
} }
func (op *OptionsProfile) InitializeUpdate(profile_name string) { func (op *OptionsProfile) InitializeUpdate(profile_name string) {
fmt.Println("Updating profile '" + profile_name + "'") fmt.Println("Updating profile '" + profile_name + "'")
op.Initialize(true) op.Initialize(true)
// Get profile data. // Get profile data.
profile := ctx.Cache.Profiles[profile_name].Profile profile := ctx.Cache.Profiles[profile_name].Profile
op.profile_name.SetText(profile.Name) op.profile_name.SetText(profile.Name)
op.binary_path.SetText(profile.Binary) op.binary_path.SetText(profile.Binary)
op.additional_parameters.SetText(profile.Additional_params) op.additional_parameters.SetText(profile.Additional_params)
if profile.Profile_path == "" { if profile.Profile_path == "" {
op.profile_path.SetText(ctx.Cfg.TEMP["DEFAULT_PROFILE_PATH"]) op.profile_path.SetText(ctx.Cfg.TEMP["DEFAULT_PROFILE_PATH"])
} else { } else {
op.profile_path.SetText(profile.Profile_path) op.profile_path.SetText(profile.Profile_path)
} }
if profile.Second_x_session == "1" { if profile.Second_x_session == "1" {
op.another_x_session.SetActive(true) op.another_x_session.SetActive(true)
} }
if profile.Version == "4.3.1" { if profile.Version == "4.3.1" {
op.urt_version_combo.SetActive(1) op.urt_version_combo.SetActive(1)
} else if profile.Version == "4.3.2" { } else if profile.Version == "4.3.2" {
op.urt_version_combo.SetActive(2) op.urt_version_combo.SetActive(2)
} else { } else {
op.urt_version_combo.SetActive(0) op.urt_version_combo.SetActive(0)
} }
op.old_profile = profile op.old_profile = profile
} }
func (op *OptionsProfile) saveProfile() { func (op *OptionsProfile) saveProfile() {
fmt.Println("Saving profile...") fmt.Println("Saving profile...")
// Validating fields. // Validating fields.
// Profile name must not be empty. // Profile name must not be empty.
if len(op.profile_name.GetText()) < 1 { if len(op.profile_name.GetText()) < 1 {
mbox_string := ctx.Translator.Translate("Empty profile name!\nProfile must be named somehow.", nil) mbox_string := ctx.Translator.Translate("Empty profile name!\nProfile must be named somehow.", nil)
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() { m.Response(func() {
m.Destroy() m.Destroy()
}) })
m.Run() m.Run()
} }
// Binary path must also be filled. // Binary path must also be filled.
if len(op.binary_path.GetText()) < 1 { if len(op.binary_path.GetText()) < 1 {
mbox_string := ctx.Translator.Translate("Empty path to binary!\nThis profile will be unusable if you\nwill not provide path to binary!", nil) mbox_string := ctx.Translator.Translate("Empty path to binary!\nThis profile will be unusable if you\nwill not provide path to binary!", nil)
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() { m.Response(func() {
m.Destroy() m.Destroy()
}) })
m.Run() m.Run()
} }
// ...and must be executable! :) // ...and must be executable! :)
_, err := os.Stat(op.binary_path.GetText()) _, err := os.Stat(op.binary_path.GetText())
if err != nil { if err != nil {
mbox_string := ctx.Translator.Translate("Invalid path to binary!\n\nError was:\n", nil) + err.Error() + ctx.Translator.Translate("\n\nCheck binary path and try again.", nil) mbox_string := ctx.Translator.Translate("Invalid path to binary!\n\nError was:\n", nil) + err.Error() + ctx.Translator.Translate("\n\nCheck binary path and try again.", nil)
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() { m.Response(func() {
m.Destroy() m.Destroy()
}) })
m.Run() m.Run()
} else { } else {
// ToDo: executable flag checking. // ToDo: executable flag checking.
//fmt.Println(filestat.Mode()) //fmt.Println(filestat.Mode())
profile_name := op.profile_name.GetText() profile_name := op.profile_name.GetText()
_, ok := ctx.Cache.Profiles[profile_name] _, ok := ctx.Cache.Profiles[profile_name]
if ok && !op.update { if ok && !op.update {
mbox_string := ctx.Translator.Translate("Game profile with same name already exist.\nRename profile for saving.", nil) mbox_string := ctx.Translator.Translate("Game profile with same name already exist.\nRename profile for saving.", nil)
m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string) m := gtk.NewMessageDialog(op.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, mbox_string)
m.Response(func() { m.Response(func() {
m.Destroy() m.Destroy()
}) })
m.Run() m.Run()
} else { } else {
ctx.Cache.CreateProfile(profile_name) ctx.Cache.CreateProfile(profile_name)
ctx.Cache.Profiles[profile_name].Profile.Name = profile_name ctx.Cache.Profiles[profile_name].Profile.Name = profile_name
ctx.Cache.Profiles[profile_name].Profile.Version = op.urt_version_combo.GetActiveText() ctx.Cache.Profiles[profile_name].Profile.Version = op.urt_version_combo.GetActiveText()
ctx.Cache.Profiles[profile_name].Profile.Binary = op.binary_path.GetText() ctx.Cache.Profiles[profile_name].Profile.Binary = op.binary_path.GetText()
ctx.Cache.Profiles[profile_name].Profile.Additional_params = op.additional_parameters.GetText() ctx.Cache.Profiles[profile_name].Profile.Additional_params = op.additional_parameters.GetText()
if op.profile_path.GetText() == "" { if op.profile_path.GetText() == "" {
ctx.Cache.Profiles[profile_name].Profile.Profile_path = "~/.q3ut4" ctx.Cache.Profiles[profile_name].Profile.Profile_path = "~/.q3ut4"
} else { } else {
ctx.Cache.Profiles[profile_name].Profile.Profile_path = op.profile_path.GetText() ctx.Cache.Profiles[profile_name].Profile.Profile_path = op.profile_path.GetText()
} }
if op.another_x_session.GetActive() { if op.another_x_session.GetActive() {
ctx.Cache.Profiles[profile_name].Profile.Second_x_session = "1" ctx.Cache.Profiles[profile_name].Profile.Second_x_session = "1"
} else { } else {
ctx.Cache.Profiles[profile_name].Profile.Second_x_session = "0" ctx.Cache.Profiles[profile_name].Profile.Second_x_session = "0"
} }
} }
} }
ctx.Eventer.LaunchEvent("flushProfiles", nil) ctx.Eventer.LaunchEvent("flushProfiles", nil)
ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{}) ctx.Eventer.LaunchEvent("loadProfilesIntoOptionsWindow", map[string]string{})
ctx.Eventer.LaunchEvent("loadProfilesIntoMainWindow", map[string]string{}) ctx.Eventer.LaunchEvent("loadProfilesIntoMainWindow", map[string]string{})
op.window.Destroy() op.window.Destroy()
} }

View File

@ -10,95 +10,95 @@
package ui package ui
import ( import (
// stdlib // stdlib
"fmt" "fmt"
"sort" "sort"
// Local // Local
"github.com/pztrn/urtrator/ioq3dataparser" "gitlab.com/pztrn/urtrator/ioq3dataparser"
// Other // Other
"github.com/mattn/go-gtk/gtk" "github.com/mattn/go-gtk/glib"
"github.com/mattn/go-gtk/glib" "github.com/mattn/go-gtk/gtk"
) )
type ServerCVarsDialog struct { type ServerCVarsDialog struct {
// Window. // Window.
window *gtk.Window window *gtk.Window
// Main Vertical Box. // Main Vertical Box.
vbox *gtk.VBox vbox *gtk.VBox
// Treeview for CVars. // Treeview for CVars.
treeview *gtk.TreeView treeview *gtk.TreeView
// Store for treeview. // Store for treeview.
treeview_store *gtk.ListStore treeview_store *gtk.ListStore
} }
func (scd *ServerCVarsDialog) Close() { func (scd *ServerCVarsDialog) Close() {
scd.window.Destroy() scd.window.Destroy()
} }
func (scd *ServerCVarsDialog) fill(srv_address string) { func (scd *ServerCVarsDialog) fill(srv_address string) {
server_info := ctx.Cache.Servers[srv_address].Server server_info := ctx.Cache.Servers[srv_address].Server
parsed_general_data := ioq3dataparser.ParseInfoToMap(server_info.ExtendedConfig) parsed_general_data := ioq3dataparser.ParseInfoToMap(server_info.ExtendedConfig)
// Sort it! // Sort it!
general_data_keys := make([]string, 0, len(parsed_general_data)) general_data_keys := make([]string, 0, len(parsed_general_data))
for k := range parsed_general_data { for k := range parsed_general_data {
general_data_keys = append(general_data_keys, k) general_data_keys = append(general_data_keys, k)
} }
sort.Strings(general_data_keys) sort.Strings(general_data_keys)
for k := range general_data_keys { for k := range general_data_keys {
iter := new(gtk.TreeIter) iter := new(gtk.TreeIter)
scd.treeview_store.Append(iter) scd.treeview_store.Append(iter)
scd.treeview_store.SetValue(iter, 0, general_data_keys[k]) scd.treeview_store.SetValue(iter, 0, general_data_keys[k])
scd.treeview_store.SetValue(iter, 1, parsed_general_data[general_data_keys[k]]) scd.treeview_store.SetValue(iter, 1, parsed_general_data[general_data_keys[k]])
} }
} }
func (scd *ServerCVarsDialog) Initialize(w *gtk.Window, srv_address string) { func (scd *ServerCVarsDialog) Initialize(w *gtk.Window, srv_address string) {
fmt.Println("Showing server's CVars...") fmt.Println("Showing server's CVars...")
scd.initializeStorages() scd.initializeStorages()
scd.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL) scd.window = gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
scd.window.SetTitle(ctx.Translator.Translate("URTrator - Server CVars", nil)) scd.window.SetTitle(ctx.Translator.Translate("URTrator - Server CVars", nil))
scd.window.Connect("destroy", scd.Close) scd.window.Connect("destroy", scd.Close)
scd.window.SetTransientFor(w) scd.window.SetTransientFor(w)
scd.window.SetDefaultSize(300, 400) scd.window.SetDefaultSize(300, 400)
scd.vbox = gtk.NewVBox(false, 0) scd.vbox = gtk.NewVBox(false, 0)
scd.window.Add(scd.vbox) scd.window.Add(scd.vbox)
// CVars scrolls. // CVars scrolls.
si := gtk.NewScrolledWindow(nil, nil) si := gtk.NewScrolledWindow(nil, nil)
scd.vbox.PackStart(si, true, true, 5) scd.vbox.PackStart(si, true, true, 5)
// CVars list. // CVars list.
scd.treeview = gtk.NewTreeView() scd.treeview = gtk.NewTreeView()
scd.treeview.SetModel(scd.treeview_store) scd.treeview.SetModel(scd.treeview_store)
si.Add(scd.treeview) si.Add(scd.treeview)
scd.treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes(ctx.Translator.Translate("Key", nil), gtk.NewCellRendererText(), "markup", 0)) scd.treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes(ctx.Translator.Translate("Key", nil), gtk.NewCellRendererText(), "markup", 0))
scd.treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes(ctx.Translator.Translate("Value", nil), gtk.NewCellRendererText(), "markup", 1)) scd.treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes(ctx.Translator.Translate("Value", nil), gtk.NewCellRendererText(), "markup", 1))
// Close button. // Close button.
hbox := gtk.NewHBox(false, 0) hbox := gtk.NewHBox(false, 0)
scd.vbox.PackStart(hbox, false, true, 5) scd.vbox.PackStart(hbox, false, true, 5)
sep := gtk.NewHBox(false, 0) sep := gtk.NewHBox(false, 0)
hbox.PackStart(sep, true, true, 5) hbox.PackStart(sep, true, true, 5)
close_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("Close", nil)) close_button := gtk.NewButtonWithLabel(ctx.Translator.Translate("Close", nil))
close_button.Clicked(scd.Close) close_button.Clicked(scd.Close)
hbox.PackStart(close_button, false, true, 5) hbox.PackStart(close_button, false, true, 5)
scd.fill(srv_address) scd.fill(srv_address)
scd.window.ShowAll() scd.window.ShowAll()
} }
func (scd *ServerCVarsDialog) initializeStorages() { func (scd *ServerCVarsDialog) initializeStorages() {
scd.treeview_store = gtk.NewListStore(glib.G_TYPE_STRING, glib.G_TYPE_STRING) scd.treeview_store = gtk.NewListStore(glib.G_TYPE_STRING, glib.G_TYPE_STRING)
} }

View File

@ -10,26 +10,26 @@
package main package main
import ( import (
// local // local
"github.com/pztrn/urtrator/common" "gitlab.com/pztrn/urtrator/common"
"github.com/pztrn/urtrator/context" "gitlab.com/pztrn/urtrator/context"
"github.com/pztrn/urtrator/ui/gtk2" "gitlab.com/pztrn/urtrator/ui/gtk2"
//"github.com/pztrn/urtrator/ui/qt5" //"github.com/pztrn/urtrator/ui/qt5"
// stdlib // stdlib
"fmt" "fmt"
"runtime" "runtime"
) )
func main() { func main() {
fmt.Println("This is URTrator, version " + common.URTRATOR_VERSION) fmt.Println("This is URTrator, version " + common.URTRATOR_VERSION)
numCPUs := runtime.NumCPU() numCPUs := runtime.NumCPU()
runtime.GOMAXPROCS(numCPUs) runtime.GOMAXPROCS(numCPUs)
ctx := context.New() ctx := context.New()
ctx.Initialize() ctx.Initialize()
ui := ui.NewMainWindow(ctx) ui := ui.NewMainWindow(ctx)
ui.Initialize() ui.Initialize()
} }