sernatur/src/place_editor.vala

565 lines
14 KiB
Vala

/*
* Copyright 2018-2019 Chris Cromer
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace Sernatur {
using LibSernatur.DB;
/**
* The place editor window class
*/
[GtkTemplate (ui = "/cl/cromer/ubb/sernatur/place.editor.ui")]
public class PlaceEditor : Gtk.ApplicationWindow {
/**
* The open database connection
*/
private Connection conn;
/**
* The place to edit
*/
private Lugar lugar;
/**
* The city data stored in the list store
*/
private enum CityColumn {
/**
* The city name
*/
CITY_NAME,
/**
* The city object
*/
CITY,
/**
* The number of colums in this enum
*/
N_COLUMNS
}
/**
* The region data stored in the list store
*/
private enum RegionColumn {
/**
* The region name
*/
REGION_NAME,
/**
* The region object
*/
REGION,
/**
* The number of colums in this enum
*/
N_COLUMNS
}
/**
* The place name
*/
[GtkChild]
private Gtk.Entry place_name;
/**
* The ticket price
*/
[GtkChild]
private Gtk.Entry ticket_price;
/**
* The difficulty
*/
[GtkChild]
private Gtk.SpinButton difficulty;
/**
* The region
*/
[GtkChild]
private Gtk.ComboBoxText region;
/**
* The save button
*/
[GtkChild]
private Gtk.Button save;
/**
* The cancel button
*/
[GtkChild]
private Gtk.Button cancel;
/**
* The city
*/
[GtkChild]
private Gtk.ComboBoxText city;
/**
* The city entry
*/
[GtkChild]
private Gtk.Entry city_entry;
/**
* A list of the cities from the database
*/
private List<Ciudad> cities;
/**
* A list of the regions from the database
*/
private List<Region> regions;
/**
* The list that stores the regions for the combo box
*/
private Gtk.ListStore region_list_store;
/**
* The list that stores the cities for the combo box
*/
private Gtk.ListStore city_list_store = null;
/**
* This signal is called when a place is saved
*/
public signal void save_place ();
[GtkCallback]
public void on_changed_combobox (Gtk.ComboBox combobox) {
if (combobox == region) {
Gtk.TreeIter iter;
region.get_active_iter (out iter);
Region temp_region;
if (region_list_store.iter_is_valid (iter)) {
// The region is from the list, not typed
region_list_store.get (iter,
RegionColumn.REGION, out temp_region);
lugar.ciudad.region = temp_region;
if (city_list_store != null && lugar.ciudad.region.id_region != 0) {
reset_city ();
}
}
}
}
/**
* Validate the tour data before trying to insert it into the database
* @return Returns true if the data is valid
*/
private bool validate_place_data () {
if (lugar.nombre_lugar.strip () == "") {
var msg = new Gtk.MessageDialog (this,
Gtk.DialogFlags.MODAL,
Gtk.MessageType.ERROR,
Gtk.ButtonsType.CLOSE,
_ ("Error: Place name cannot be left blank!"));
msg.response.connect ((response_id) => {
msg.destroy ();
});
msg.set_title (_ ("Error"));
msg.run ();
return false;
}
bool list_success = true;
try {
List<Lugar> list = Lugar.get_all_lugares (conn);
list.foreach ((entry) => {
if (lugar.nombre_lugar.down () == entry.nombre_lugar.down () && lugar.id_lugar != entry.id_lugar) {
var msg = new Gtk.MessageDialog (this,
Gtk.DialogFlags.MODAL,
Gtk.MessageType.ERROR,
Gtk.ButtonsType.CLOSE,
_ ("Error: A place named \"%s\" already exists!"), entry.nombre_lugar);
msg.response.connect ((response_id) => {
msg.destroy ();
});
msg.set_title (_ ("Error"));
msg.run ();
list_success = false;
}
});
}
catch (Error e) {
#if DEBUG
error (e.message);
#else
warning (e.message);
return false;
#endif
}
return list_success;
}
/**
* Validate the city data before trying to insert it into the database
* @param ciudad The city to validate
* @return Returns true if the data is valid
*/
private bool validate_city_data (Ciudad ciudad) {
if (ciudad.nombre_ciudad.strip () == "") {
var msg = new Gtk.MessageDialog (this,
Gtk.DialogFlags.MODAL,
Gtk.MessageType.ERROR,
Gtk.ButtonsType.CLOSE,
_ ("Error: City name cannot be left blank!"));
msg.response.connect ((response_id) => {
msg.destroy ();
});
msg.set_title (_ ("Error"));
msg.run ();
return false;
}
bool list_success = true;
try {
List<Ciudad> list = Ciudad.get_all_ciudades (conn);
list.foreach ((entry) => {
if (ciudad.nombre_ciudad.down () == entry.nombre_ciudad.down ()) {
var msg = new Gtk.MessageDialog (this,
Gtk.DialogFlags.MODAL,
Gtk.MessageType.ERROR,
Gtk.ButtonsType.CLOSE,
_ ("Error: A city named \"%s\" already exists!"), entry.nombre_ciudad);
msg.response.connect ((response_id) => {
msg.destroy ();
});
msg.set_title (_ ("Error"));
msg.run ();
list_success = false;
}
});
}
catch (Error e) {
#if DEBUG
error (e.message);
#else
warning (e.message);
return false;
#endif
}
return list_success;
}
/**
* Validate the region data before trying to insert it into the database
* @param region The region to validate
* @return Returns true if the data is valid
*/
private bool validate_region_data (Region region) {
if (region.nombre_region.strip () == "") {
var msg = new Gtk.MessageDialog (this,
Gtk.DialogFlags.MODAL,
Gtk.MessageType.ERROR,
Gtk.ButtonsType.CLOSE,
_ ("Error: Region name cannot be left blank!"));
msg.response.connect ((response_id) => {
msg.destroy ();
});
msg.set_title (_ ("Error"));
msg.run ();
return false;
}
bool list_success = true;
try {
List<Region> list = Region.get_all_regiones (conn);
list.foreach ((entry) => {
if (region.nombre_region.down () == entry.nombre_region.down ()) {
var msg = new Gtk.MessageDialog (this,
Gtk.DialogFlags.MODAL,
Gtk.MessageType.ERROR,
Gtk.ButtonsType.CLOSE,
_ ("Error: A region named \"%s\" already exists!"), entry.nombre_region);
msg.response.connect ((response_id) => {
msg.destroy ();
});
msg.set_title (_ ("Error"));
msg.run ();
list_success = false;
}
});
}
catch (Error e) {
#if DEBUG
error (e.message);
#else
warning (e.message);
return false;
#endif
}
return list_success;
}
/**
* Reset the city dropdown
*/
private void reset_city () {
try {
cities = Ciudad.get_all_ciudades_in_region (conn, lugar.ciudad.region.id_region);
}
catch (Error e) {
#if DEBUG
error (e.message);
#else
warning (e.message);
#endif
}
if (cities.length () > 0) {
cities.sort_with_data ((a, b) => {
return strcmp (a.nombre_ciudad, b.nombre_ciudad);
});
if (city_list_store.iter_n_children (null) > 0) {
// If there are more than 0 rows clear it
city_list_store.clear ();
}
cities.foreach ((entry) => {
Gtk.TreeIter iter;
city_list_store.append (out iter);
city_list_store.set (iter,
CityColumn.CITY_NAME, entry.nombre_ciudad,
CityColumn.CITY, entry);
if (lugar.ciudad.id_ciudad == 0) {
lugar.ciudad.id_ciudad = entry.id_ciudad;
lugar.ciudad.nombre_ciudad = entry.nombre_ciudad;
}
else {
if (entry.id_ciudad == lugar.ciudad.id_ciudad) {
city.set_active_iter (iter);
}
}
});
}
city.set_active (-1);
city_entry.set_text ("");
}
/**
* This callback is called when a button is clicked
* @param button The button that was clicked
*/
[GtkCallback]
public void on_clicked_button (Gtk.Button button) {
if (button == save) {
if (update_place_instance () && validate_place_data ()) {
if (lugar.id_lugar == 0) {
update_place_instance ();
try {
Lugar.insert_place (conn, lugar);
}
catch (Error e) {
#if DEBUG
error (e.message);
#else
warning (e.message);
#endif
}
finally {
save_place (); // Signal the parent to update itself
this.close ();
}
}
else {
update_place_instance ();
try {
Lugar.update_place (conn, lugar);
}
catch (Error e) {
#if DEBUG
error (e.message);
#else
warning (e.message);
#endif
}
finally {
save_place (); // Signal the parent to update itself
this.close ();
}
}
}
}
else if (button == cancel) {
this.close ();
}
}
/**
* Update the the place object with new info from the editor
*/
private bool update_place_instance () {
lugar.nombre_lugar = place_name.get_text ();
lugar.valor_entrada = (uint) int.parse (ticket_price.get_text ());
lugar.nivel = (uint) difficulty.get_value_as_int ();
if (region.get_active () == -1) {
Region new_region = new Region (0, region.get_active_text ());
try {
if (validate_region_data (new_region)) {
new_region.id_region = Region.insert_region (conn, new_region);
return update_place_instance_city (new_region);
}
else {
return false;
}
}
catch (Error e) {
#if DEBUG
error (e.message);
#else
warning (e.message);
#endif
}
}
else {
Region new_region;
Gtk.TreeIter iter;
region.get_active_iter (out iter);
if (region_list_store.iter_is_valid (iter)) {
region_list_store.get (iter,
RegionColumn.REGION, out new_region);
}
else {
new_region = new Region ();
}
return update_place_instance_city (new_region);
}
return true;
}
/**
* This method updates the city part of the lugar instance
* @param new_region The region to insert into the city object
*/
private bool update_place_instance_city (Region new_region) {
Ciudad ciudad;
if (city.get_active () == -1) {
ciudad = new Ciudad (0, city.get_active_text ());
ciudad.region = new_region;
try {
if (validate_city_data (ciudad)) {
ciudad.id_ciudad = Ciudad.insert_city (conn, ciudad);
}
else {
return false;
}
}
catch (Error e) {
#if DEBUG
error (e.message);
#else
warning (e.message);
#endif
}
finally {
lugar.ciudad = ciudad;
}
}
else {
Gtk.TreeIter iter;
city.get_active_iter (out iter);
if (city_list_store.iter_is_valid (iter)) {
city_list_store.get (iter,
CityColumn.CITY, out ciudad);
ciudad.region = new_region;
lugar.ciudad = ciudad;
}
}
return true;
}
/**
* Initialize the place editor class
* @param application The application used to make the GLib object
* @param conn The database connection to use
* @param lugar The place to edit
*/
public PlaceEditor (Gtk.Application application, Connection conn, Lugar? lugar) {
Object (application: application);
this.conn = conn;
this.lugar = lugar;
}
/**
* Initialize what is needed for this window
*/
public void initialize () {
try {
regions = Region.get_all_regiones (conn);
}
catch (Error e) {
#if DEBUG
error (e.message);
#else
warning (e.message);
#endif
}
regions.sort_with_data ((a, b) => {
return strcmp (a.nombre_region, b.nombre_region);
});
region_list_store = new Gtk.ListStore (RegionColumn.N_COLUMNS,
typeof (string),
typeof (Region));
region.set_model (region_list_store);
if (lugar != null) {
place_name.set_text (lugar.nombre_lugar);
ticket_price.set_text (lugar.valor_entrada.to_string ());
difficulty.set_text (lugar.nivel.to_string ());
}
else {
lugar = new Lugar ();
lugar.ciudad = new Ciudad ();
lugar.ciudad.region = new Region ();
}
regions.foreach ((entry) => {
Gtk.TreeIter iter;
region_list_store.append (out iter);
region_list_store.set (iter,
RegionColumn.REGION_NAME, entry.nombre_region,
RegionColumn.REGION, entry);
if (entry.id_region == lugar.ciudad.region.id_region) {
region.set_active_iter (iter);
}
});
region.set_entry_text_column (RegionColumn.REGION_NAME);
city_list_store = new Gtk.ListStore (CityColumn.N_COLUMNS,
typeof (string),
typeof (Ciudad));
city.set_model (city_list_store);
try {
cities = Ciudad.get_all_ciudades_in_region (conn, lugar.ciudad.region.id_region);
}
catch (Error e) {
#if DEBUG
error (e.message);
#else
warning (e.message);
#endif
}
if (cities.length () > 0) {
cities.sort_with_data ((a, b) => {
return strcmp (a.nombre_ciudad, b.nombre_ciudad);
});
cities.foreach ((entry) => {
Gtk.TreeIter iter;
city_list_store.append (out iter);
city_list_store.set (iter,
CityColumn.CITY_NAME, entry.nombre_ciudad,
CityColumn.CITY, entry);
if (entry.id_ciudad == lugar.ciudad.id_ciudad) {
city.set_active_iter (iter);
}
});
}
}
}
}