1 //  Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2014, 2015,
2 //  2020 Ben Asselstine
3 //
4 //  This program is free software; you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation; either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU Library General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program; if not, write to the Free Software
16 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 //  02110-1301, USA.
18 
19 #include <config.h>
20 
21 #include <iostream>
22 #include <errno.h>
23 #include <sigc++/functors/mem_fun.h>
24 #include <sigc++/functors/ptr_fun.h>
25 
26 #include <gtkmm.h>
27 #include "armyset-window.h"
28 #include "builder-cache.h"
29 #include "armyset-info-dialog.h"
30 #include "masked-image-editor-dialog.h"
31 
32 #include "defs.h"
33 #include "Configuration.h"
34 #include "ImageCache.h"
35 #include "armysetlist.h"
36 #include "Tile.h"
37 #include "File.h"
38 #include "shield.h"
39 #include "shieldsetlist.h"
40 #include "editor-quit-dialog.h"
41 #include "editor-save-changes-dialog.h"
42 
43 #include "ucompose.hpp"
44 
45 #include "image-editor-dialog.h"
46 #include "playerlist.h"
47 #include "GameMap.h"
48 #include "font-size.h"
49 #include "timed-message-dialog.h"
50 
51 #define method(x) sigc::mem_fun(*this, &ArmySetWindow::x)
52 
ArmySetWindow(Glib::ustring load_filename)53 ArmySetWindow::ArmySetWindow(Glib::ustring load_filename)
54 {
55   needs_saving = false;
56   inhibit_needs_saving = false;
57   d_armyset = NULL;
58   Glib::RefPtr<Gtk::Builder> xml = BuilderCache::editor_get("armyset-window.ui");
59 
60   xml->get_widget("window", window);
61   window->set_icon_from_file(File::getVariousFile("castle_icon.png"));
62   window->signal_delete_event().connect (method(on_window_closed));
63 
64   xml->get_widget("white_image", white_image);
65   xml->get_widget("make_same_button", make_same_button);
66   make_same_button->signal_clicked().connect (method(on_make_same_clicked));
67   xml->get_widget("green_image", green_image);
68   xml->get_widget("yellow_image", yellow_image);
69   xml->get_widget("light_blue_image", light_blue_image);
70   xml->get_widget("red_image", red_image);
71   xml->get_widget("dark_blue_image", dark_blue_image);
72   xml->get_widget("orange_image", orange_image);
73   xml->get_widget("black_image", black_image);
74   xml->get_widget("neutral_image", neutral_image);
75   xml->get_widget("name_entry", name_entry);
76   name_entry->signal_changed().connect (method(on_name_changed));
77   xml->get_widget("armies_treeview", armies_treeview);
78   xml->get_widget("armies_scrolledwindow", armies_scrolledwindow);
79   xml->get_widget("description_textview", description_textview);
80   description_textview->get_buffer()->signal_changed().connect
81     (method(on_description_changed));
82   xml->get_widget("white_image_button", white_image_button);
83   white_image_button->signal_clicked().connect
84     (sigc::bind(method(on_image_changed), Shield::WHITE));
85   xml->get_widget("green_image_button", green_image_button);
86   green_image_button->signal_clicked().connect
87     (sigc::bind(method(on_image_changed), Shield::GREEN));
88   xml->get_widget("yellow_image_button", yellow_image_button);
89   yellow_image_button->signal_clicked().connect
90     (sigc::bind(method(on_image_changed), Shield::YELLOW));
91   xml->get_widget("light_blue_image_button", light_blue_image_button);
92   light_blue_image_button->signal_clicked().connect
93     (sigc::bind(method(on_image_changed), Shield::LIGHT_BLUE));
94   xml->get_widget("red_image_button", red_image_button);
95   red_image_button->signal_clicked().connect
96     (sigc::bind(method(on_image_changed), Shield::RED));
97   xml->get_widget("dark_blue_image_button", dark_blue_image_button);
98   dark_blue_image_button->signal_clicked().connect
99     (sigc::bind(method(on_image_changed), Shield::DARK_BLUE));
100   xml->get_widget("orange_image_button", orange_image_button);
101   orange_image_button->signal_clicked().connect
102     (sigc::bind(method(on_image_changed), Shield::ORANGE));
103   xml->get_widget("black_image_button", black_image_button);
104   black_image_button->signal_clicked().connect
105     (sigc::bind(method(on_image_changed), Shield::BLACK));
106   xml->get_widget("neutral_image_button", neutral_image_button);
107   neutral_image_button->signal_clicked().connect
108     (sigc::bind(method(on_image_changed), Shield::NEUTRAL));
109   xml->get_widget("production_spinbutton", production_spinbutton);
110   production_spinbutton->set_range
111     (double(MIN_PRODUCTION_TURNS_FOR_ARMY_UNITS),
112      double(MAX_PRODUCTION_TURNS_FOR_ARMY_UNITS));
113   production_spinbutton->signal_changed().connect (method(on_production_changed));
114   production_spinbutton->signal_insert_text().connect
115     (sigc::hide(sigc::hide(method(on_production_text_changed))));
116   xml->get_widget("cost_spinbutton", cost_spinbutton);
117   cost_spinbutton->set_range(double(MIN_COST_FOR_ARMY_UNITS),
118                              double(MAX_COST_FOR_ARMY_UNITS));
119   cost_spinbutton->signal_changed().connect (method(on_cost_changed));
120   cost_spinbutton->signal_insert_text().connect
121     (sigc::hide(sigc::hide(method(on_cost_text_changed))));
122   xml->get_widget("new_cost_spinbutton", new_cost_spinbutton);
123   new_cost_spinbutton->set_range(double(MIN_NEW_COST_FOR_ARMY_UNITS),
124                                  double(MAX_NEW_COST_FOR_ARMY_UNITS));
125   new_cost_spinbutton->signal_changed().connect (method(on_new_cost_changed));
126   new_cost_spinbutton->signal_insert_text().connect
127     (sigc::hide(sigc::hide(method(on_new_cost_text_changed))));
128   xml->get_widget("upkeep_spinbutton", upkeep_spinbutton);
129   upkeep_spinbutton->set_range (double(MIN_UPKEEP_FOR_ARMY_UNITS),
130                                 double(MAX_UPKEEP_FOR_ARMY_UNITS));
131   upkeep_spinbutton->signal_changed().connect (method(on_upkeep_changed));
132   upkeep_spinbutton->signal_insert_text().connect
133     (sigc::hide(sigc::hide(method(on_upkeep_text_changed))));
134   xml->get_widget("strength_spinbutton", strength_spinbutton);
135   strength_spinbutton->set_range (double(MIN_STRENGTH_FOR_ARMY_UNITS),
136                                   double(MAX_STRENGTH_FOR_ARMY_UNITS));
137   strength_spinbutton->signal_changed().connect (method(on_strength_changed));
138   strength_spinbutton->signal_insert_text().connect
139     (sigc::hide(sigc::hide(method(on_strength_text_changed))));
140   xml->get_widget("moves_spinbutton", moves_spinbutton);
141   moves_spinbutton->set_range(double(MIN_MOVES_FOR_ARMY_UNITS),
142                               double(MAX_MOVES_FOR_ARMY_UNITS));
143   moves_spinbutton->signal_changed().connect (method(on_moves_changed));
144   moves_spinbutton->signal_insert_text().connect
145     (sigc::hide(sigc::hide(method(on_moves_text_changed))));
146   xml->get_widget("exp_spinbutton", exp_spinbutton);
147   exp_spinbutton->set_range(double(MIN_EXP_FOR_ARMY_UNITS),
148                             double(MAX_EXP_FOR_ARMY_UNITS));
149   exp_spinbutton->signal_changed().connect (method(on_exp_changed));
150   exp_spinbutton->signal_insert_text().connect
151     (sigc::hide(sigc::hide(method(on_exp_text_changed))));
152   xml->get_widget("hero_combobox", hero_combobox);
153   hero_combobox->signal_changed().connect (method(on_hero_combobox_changed));
154   xml->get_widget("awardable_switch", awardable_switch);
155   awardable_switch->property_active().signal_changed().connect (method(on_awardable_toggled));
156   xml->get_widget("defends_ruins_switch", defends_ruins_switch);
157   defends_ruins_switch->property_active().signal_changed().connect (method(on_defends_ruins_toggled));
158   xml->get_widget("sight_spinbutton", sight_spinbutton);
159   sight_spinbutton->set_range(double(MIN_SIGHT_FOR_ARMY_UNITS),
160                               double(MAX_SIGHT_FOR_ARMY_UNITS));
161   sight_spinbutton->signal_changed().connect (method(on_sight_changed));
162   sight_spinbutton->signal_insert_text().connect
163     (sigc::hide(sigc::hide(method(on_sight_text_changed))));
164   xml->get_widget("id_spinbutton", id_spinbutton);
165   id_spinbutton->set_range(0, 1000);
166   id_spinbutton->signal_changed().connect (method(on_id_changed));
167   id_spinbutton->signal_insert_text().connect
168     (sigc::hide(sigc::hide(method(on_id_text_changed))));
169   xml->get_widget("move_forests_switch", move_forests_switch);
170   move_forests_switch->property_active().signal_changed().connect
171     (sigc::bind(method(on_movebonus_toggled),
172                 move_forests_switch, Tile::FOREST));
173   xml->get_widget("move_marshes_switch", move_marshes_switch);
174   move_marshes_switch->property_active().signal_changed().connect
175     (sigc::bind(method(on_movebonus_toggled),
176                 move_marshes_switch, Tile::SWAMP));
177   xml->get_widget("move_hills_switch", move_hills_switch);
178   move_hills_switch->property_active().signal_changed().connect
179     (sigc::bind(method(on_movebonus_toggled),
180                 move_hills_switch, Tile::HILLS));
181   xml->get_widget("move_mountains_switch", move_mountains_switch);
182   move_mountains_switch->property_active().signal_changed().connect
183     (sigc::bind(method(on_movebonus_toggled),
184                 move_mountains_switch, Tile::MOUNTAIN));
185   xml->get_widget("can_fly_switch", can_fly_switch);
186   can_fly_switch->property_active().signal_changed().connect
187     (sigc::bind(method(on_movebonus_toggled),
188                 can_fly_switch, Tile::GRASS | Tile::WATER |
189                 Tile::FOREST | Tile::HILLS | Tile::MOUNTAIN | Tile::SWAMP));
190   xml->get_widget("add1strinopen_switch", add1strinopen_switch);
191   add1strinopen_switch->property_active().signal_changed().connect
192     (sigc::bind(method(on_armybonus_toggled), add1strinopen_switch,
193                 Army::ADD1STRINOPEN));
194   xml->get_widget("add2strinopen_switch", add2strinopen_switch);
195   add2strinopen_switch->property_active().signal_changed().connect
196     (sigc::bind(method(on_armybonus_toggled), add2strinopen_switch,
197                 Army::ADD2STRINOPEN));
198   xml->get_widget("add1strinforest_switch", add1strinforest_switch);
199   add1strinforest_switch->property_active().signal_changed().connect
200     (sigc::bind(method(on_armybonus_toggled), add1strinforest_switch,
201                 Army::ADD1STRINFOREST));
202   xml->get_widget("add2strinforest_switch", add2strinforest_switch);
203   add2strinforest_switch->property_active().signal_changed().connect
204     (sigc::bind(method(on_armybonus_toggled), add2strinforest_switch,
205                 Army::ADD2STRINFOREST));
206   xml->get_widget("add1strinhills_switch", add1strinhills_switch);
207   add1strinhills_switch->property_active().signal_changed().connect
208     (sigc::bind(method(on_armybonus_toggled), add1strinhills_switch,
209                 Army::ADD1STRINHILLS));
210   xml->get_widget("add2strinhills_switch", add2strinhills_switch);
211   add2strinhills_switch->property_active().signal_changed().connect
212     (sigc::bind(method(on_armybonus_toggled), add2strinhills_switch,
213                 Army::ADD2STRINHILLS));
214   xml->get_widget("add1strincity_switch", add1strincity_switch);
215   add1strincity_switch->property_active().signal_changed().connect
216     (sigc::bind(method(on_armybonus_toggled), add1strincity_switch,
217                 Army::ADD1STRINCITY));
218   xml->get_widget("add2strincity_switch", add2strincity_switch);
219   add2strincity_switch->property_active().signal_changed().connect
220     (sigc::bind(method (on_armybonus_toggled), add2strincity_switch,
221                 Army::ADD2STRINCITY));
222   xml->get_widget("add1stackinhills_switch",
223                   add1stackinhills_switch);
224   add1stackinhills_switch->property_active().signal_changed().connect
225     (sigc::bind(method (on_armybonus_toggled), add1stackinhills_switch,
226                 Army::ADD1STACKINHILLS));
227   xml->get_widget("suballcitybonus_switch", suballcitybonus_switch);
228   suballcitybonus_switch->property_active().signal_changed().connect
229     (sigc::bind(method (on_armybonus_toggled), suballcitybonus_switch,
230                 Army::SUBALLCITYBONUS));
231   xml->get_widget("sub1enemystack_switch", sub1enemystack_switch);
232   sub1enemystack_switch->property_active().signal_changed().connect
233     (sigc::bind(method (on_armybonus_toggled),
234                 sub1enemystack_switch, Army::SUB1ENEMYSTACK));
235   xml->get_widget("sub2enemystack_switch", sub2enemystack_switch);
236   sub2enemystack_switch->property_active().signal_changed().connect
237     (sigc::bind(method(on_armybonus_toggled), sub2enemystack_switch,
238                 Army::SUB2ENEMYSTACK));
239   xml->get_widget("add1stack_switch", add1stack_switch);
240   add1stack_switch->property_active().signal_changed().connect
241     (sigc::bind(method(on_armybonus_toggled), add1stack_switch,
242                 Army::ADD1STACK));
243   xml->get_widget("add2stack_switch", add2stack_switch);
244   add2stack_switch->property_active().signal_changed().connect
245     (sigc::bind(method (on_armybonus_toggled), add2stack_switch,
246                 Army::ADD2STACK));
247   xml->get_widget("suballnonherobonus_switch",
248                   suballnonherobonus_switch);
249   suballnonherobonus_switch->property_active().signal_changed().connect
250     (sigc::bind(method (on_armybonus_toggled), suballnonherobonus_switch,
251                 Army::SUBALLNONHEROBONUS));
252   xml->get_widget("suballherobonus_switch", suballherobonus_switch);
253   suballherobonus_switch->property_active().signal_changed().connect
254     (sigc::bind(method(on_armybonus_toggled), suballherobonus_switch,
255                 Army::SUBALLHEROBONUS));
256   xml->get_widget("add_army_button", add_army_button);
257   add_army_button->signal_clicked().connect (method(on_add_army_clicked));
258   xml->get_widget("remove_army_button", remove_army_button);
259   remove_army_button->signal_clicked().connect (method(on_remove_army_clicked));
260   xml->get_widget("army_vbox", army_vbox);
261   // connect callbacks for the menu
262   xml->get_widget("new_armyset_menuitem", new_armyset_menuitem);
263   new_armyset_menuitem->signal_activate().connect (method(on_new_armyset_activated));
264   xml->get_widget("load_armyset_menuitem", load_armyset_menuitem);
265   load_armyset_menuitem->signal_activate().connect (method(on_load_armyset_activated));
266   xml->get_widget("save_armyset_menuitem", save_armyset_menuitem);
267   save_armyset_menuitem->signal_activate().connect (method(on_save_armyset_activated));
268   xml->get_widget("save_as_menuitem", save_as_menuitem);
269   save_as_menuitem->signal_activate().connect (method(on_save_as_activated));
270   xml->get_widget("validate_armyset_menuitem", validate_armyset_menuitem);
271   validate_armyset_menuitem->signal_activate().connect
272     (method(on_validate_armyset_activated));
273   xml->get_widget("quit_menuitem", quit_menuitem);
274   quit_menuitem->signal_activate().connect (method(on_quit_activated));
275   xml->get_widget("edit_armyset_info_menuitem", edit_armyset_info_menuitem);
276   edit_armyset_info_menuitem->signal_activate().connect
277     (method(on_edit_armyset_info_activated));
278   xml->get_widget("edit_standard_picture_menuitem", edit_standard_picture_menuitem);
279   edit_standard_picture_menuitem->signal_activate().connect
280     (method(on_edit_standard_picture_activated));
281   xml->get_widget("edit_bag_picture_menuitem", edit_bag_picture_menuitem);
282   edit_bag_picture_menuitem->signal_activate().connect
283     (method(on_edit_bag_picture_activated));
284   xml->get_widget("edit_ship_picture_menuitem", edit_ship_picture_menuitem);
285   edit_ship_picture_menuitem->signal_activate().connect
286     (method(on_edit_ship_picture_activated));
287   xml->get_widget ("help_about_menuitem", help_about_menuitem);
288   help_about_menuitem->signal_activate().connect (method(on_help_about_activated));
289   xml->get_widget ("tutorial_menuitem", tutorial_menuitem);
290   tutorial_menuitem->signal_activate().connect (method(on_tutorial_video_activated));
291   xml->get_widget("notebook", notebook);
292 
293   armies_list = Gtk::ListStore::create(armies_columns);
294   armies_treeview->set_model(armies_list);
295   armies_treeview->append_column("", armies_columns.name);
296   armies_treeview->set_headers_visible(false);
297   armies_treeview->get_selection()->signal_changed().connect(method(on_army_selected));
298   armies_treeview->set_reorderable(true);
299   armies_list->signal_row_inserted().connect(sigc::hide(sigc::hide(method(on_army_moved))));
300 
301   if (load_filename != "")
302     current_save_filename = load_filename;
303   update_army_panel();
304   update_armyset_buttons();
305 
306   if (load_filename.empty() == false)
307     {
308       load_armyset (load_filename);
309       update_armyset_buttons();
310       update_army_panel();
311     }
312   inhibit_scrolldown = true;
313   //we only want inhibit scrolldown to be false when we click add, and we
314   //want the scrolledwindow to scroll down to the bottom.
315   //the problem is that an army gets selected as a result of an add.
316   //which is fine, but then there are also other times when an army gets
317   //selected.  like the with the mouse.
318   inhibit_updates = false;
319 }
320 
321 void
update_armyset_buttons()322 ArmySetWindow::update_armyset_buttons()
323 {
324   if (!armies_treeview->get_selection()->get_selected())
325     remove_army_button->set_sensitive(false);
326   else
327     remove_army_button->set_sensitive(true);
328   if (d_armyset == NULL)
329     add_army_button->set_sensitive(false);
330   else
331     add_army_button->set_sensitive(true);
332 }
333 
334 void
update_army_panel()335 ArmySetWindow::update_army_panel()
336 {
337   //if nothing selected in the treeview, then we don't show anything in
338   //the army panel
339   if (armies_treeview->get_selection()->get_selected() == 0)
340     {
341       //clear all values
342       inhibit_needs_saving = true;
343       name_entry->set_text("");
344       description_textview->get_buffer()->set_text("");
345       production_spinbutton->set_value(MIN_PRODUCTION_TURNS_FOR_ARMY_UNITS);
346       cost_spinbutton->set_value(MIN_COST_FOR_ARMY_UNITS);
347       new_cost_spinbutton->set_value(MIN_NEW_COST_FOR_ARMY_UNITS);
348       upkeep_spinbutton->set_value(MIN_UPKEEP_FOR_ARMY_UNITS);
349       strength_spinbutton->set_value(MIN_STRENGTH_FOR_ARMY_UNITS);
350       moves_spinbutton->set_value(MIN_MOVES_FOR_ARMY_UNITS);
351       exp_spinbutton->set_value(0);
352 
353       hero_combobox->set_active (0);
354       awardable_switch->set_active(false);
355       defends_ruins_switch->set_active(false);
356       sight_spinbutton->set_value(0);
357       id_spinbutton->set_value(0);
358       move_forests_switch->set_active(false);
359       move_marshes_switch->set_active(false);
360       move_hills_switch->set_active(false);
361       move_mountains_switch->set_active(false);
362       can_fly_switch->set_active(false);
363       add1strinopen_switch->set_active(false);
364       add2strinopen_switch->set_active(false);
365       add1strinforest_switch->set_active(false);
366       add1strinhills_switch->set_active(false);
367       add1strincity_switch->set_active(false);
368       add2strincity_switch->set_active(false);
369       add1stackinhills_switch->set_active(false);
370       suballcitybonus_switch->set_active(false);
371       sub1enemystack_switch->set_active(false);
372       add1stack_switch->set_active(false);
373       add2stack_switch->set_active(false);
374       suballnonherobonus_switch->set_active(false);
375       suballherobonus_switch->set_active(false);
376       white_image->clear();
377       green_image->clear();
378       yellow_image->clear();
379       light_blue_image->clear();
380       red_image->clear();
381       dark_blue_image->clear();
382       orange_image->clear();
383       black_image->clear();
384       neutral_image->clear();
385       army_vbox->set_sensitive(false);
386       inhibit_needs_saving = false;
387       return;
388     }
389   army_vbox->set_sensitive(true);
390   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
391   Gtk::TreeModel::iterator iterrow = selection->get_selected();
392 
393   if (iterrow)
394     {
395       // Row selected
396       Gtk::TreeModel::Row row = *iterrow;
397 
398       ArmyProto *a = row[armies_columns.army];
399       inhibit_needs_saving = true;
400       fill_army_info(a);
401       inhibit_needs_saving = false;
402     }
403 }
404 
on_new_armyset_activated()405 void ArmySetWindow::on_new_armyset_activated()
406 {
407   make_new_armyset ();
408 }
409 
make_new_armyset()410 bool ArmySetWindow::make_new_armyset ()
411 {
412   Glib::ustring msg = _("Save these changes before making a new Army Set?");
413   if (check_discard (msg) == false)
414     return false;
415   save_armyset_menuitem->set_sensitive (false);
416   current_save_filename = "";
417   if (d_armyset)
418     delete d_armyset;
419 
420   guint32 num = 0;
421   Glib::ustring name =
422     Armysetlist::getInstance()->findFreeName(_("Untitled"), 100, num,
423                                              Armyset::get_default_tile_size ());
424 
425   d_armyset = new Armyset (Armysetlist::getNextAvailableId (1), name);
426   d_armyset->setNewTemporaryFile ();
427 
428   inhibit_updates = true;
429   armies_list->clear();
430   inhibit_updates = false;
431 
432 
433   refresh_armies ();
434   update_army_panel ();
435   needs_saving = true;
436   update_window_title();
437   return true;
438 }
439 
on_load_armyset_activated()440 void ArmySetWindow::on_load_armyset_activated()
441 {
442   load_armyset ();
443 }
444 
load_armyset()445 bool ArmySetWindow::load_armyset ()
446 {
447   bool ret = false;
448   Glib::ustring msg = _("Save these changes before opening a new Army Set?");
449   if (check_discard (msg) == false)
450     return ret;
451   Gtk::FileChooserDialog chooser(*window,
452 				 _("Choose an Army Set to Open"));
453   Glib::RefPtr<Gtk::FileFilter> lwa_filter = Gtk::FileFilter::create();
454   lwa_filter->set_name(_("LordsAWar Army Sets (*.lwa)"));
455   lwa_filter->add_pattern("*" + ARMYSET_EXT);
456   chooser.add_filter(lwa_filter);
457   chooser.set_current_folder(File::getSetDir(Armyset::file_extension, false));
458 
459   chooser.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
460   chooser.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
461   chooser.set_default_response(Gtk::RESPONSE_ACCEPT);
462 
463   chooser.show_all();
464   int res = chooser.run();
465 
466   if (res == Gtk::RESPONSE_ACCEPT)
467     {
468       bool ok = load_armyset(chooser.get_filename());
469       chooser.hide();
470       if (ok)
471         {
472           needs_saving = false;
473           update_window_title();
474           ret = true;
475         }
476     }
477 
478   refresh_armies ();
479   update_army_panel ();
480   return ret;
481 }
482 
on_validate_armyset_activated()483 void ArmySetWindow::on_validate_armyset_activated()
484 {
485   std::list<Glib::ustring> msgs;
486   if (d_armyset == NULL)
487     return;
488   bool valid;
489   valid = String::utrim (d_armyset->getName ()) != "";
490   if (!valid)
491     {
492       Glib::ustring s = _("The name of the Army Set is invalid.");
493       msgs.push_back(s);
494     }
495   valid = d_armyset->size() > 0;
496   if (!valid)
497     msgs.push_back(_("There must be at least one army unit in the Army Set."));
498   valid = d_armyset->validateHero();
499   if (!valid)
500     msgs.push_back(_("There must be at least one hero in the Army Set."));
501   valid = d_armyset->validatePurchasables();
502   if (!valid)
503     msgs.push_back(_("There must be at least one army unit with a production cost of more than zero."));
504   valid = d_armyset->validateRuinDefenders();
505   if (!valid)
506     msgs.push_back(_("There must be at least one army unit than can defend a ruin."));
507   valid = d_armyset->validateAwardables();
508   if (!valid)
509     msgs.push_back(_("There must be at least one army unit than can be awarded to a hero."));
510   valid = d_armyset->validateShip();
511   if (!valid)
512     msgs.push_back(_("The ship image must be set."));
513   valid = d_armyset->validateStandard();
514   if (!valid)
515     msgs.push_back(_("The hero's standard (the flag) image must be set."));
516   valid = d_armyset->validateBag();
517   if (!valid)
518     msgs.push_back(_("The picture for the bag of items must be set."));
519 
520   for (Armyset::iterator it = d_armyset->begin(); it != d_armyset->end(); it++)
521     {
522       Shield::Colour c;
523       valid = d_armyset->validateArmyUnitImage(*it, c);
524       if (!valid)
525         {
526           msgs.push_back(String::ucompose(_("%1 does not have an image for the %2 player"), (*it)->getName(), Shield::colourToString(c)));
527           break;
528         }
529     }
530 
531   valid = d_armyset->validateArmyUnitNames();
532   if (!valid)
533     msgs.push_back(_("An army unit does not have a name."));
534 
535   if (msgs.empty() == true && isValidName () == false)
536     msgs.push_back(_("The name of the Army Set is not unique."));
537 
538   Glib::ustring msg = "";
539   for (std::list<Glib::ustring>::iterator it = msgs.begin(); it != msgs.end();
540        it++)
541     {
542       msg += (*it) + "\n";
543       break;
544     }
545 
546   if (msg == "")
547     msg = _("The Army Set is valid.");
548 
549   TimedMessageDialog dialog(*window, msg, 0);
550   dialog.run_and_hide();
551   return;
552 }
553 
on_save_as_activated()554 void ArmySetWindow::on_save_as_activated()
555 {
556   if (check_save_valid (false))
557     save_current_armyset_file_as ();
558 }
559 
sync_armies()560 void ArmySetWindow::sync_armies ()
561 {
562   //Reorder the armyset according to the treeview
563   d_armyset->clear ();
564   guint32 id = 0;
565   for (Gtk::TreeIter i = armies_list->children ().begin (),
566        end = armies_list->children ().end (); i != end; ++i)
567     {
568       ArmyProto *army = (*i)[armies_columns.army];
569       if (army)
570         {
571           army->setId (id);
572           id++;
573           d_armyset->push_back (army);
574         }
575     }
576 }
577 
save_current_armyset_file_as()578 bool ArmySetWindow::save_current_armyset_file_as ()
579 {
580   sync_armies ();
581 
582   bool ret = false;
583   while (1)
584     {
585       Gtk::FileChooserDialog chooser(*window, _("Choose a Name"),
586                                      Gtk::FILE_CHOOSER_ACTION_SAVE);
587       Glib::RefPtr<Gtk::FileFilter> lwa_filter = Gtk::FileFilter::create();
588       lwa_filter->set_name(_("LordsAWar Army Sets (*.lwa)"));
589       lwa_filter->add_pattern("*" + ARMYSET_EXT);
590       chooser.add_filter(lwa_filter);
591       chooser.set_current_folder(File::getSetDir(ARMYSET_EXT, false));
592 
593       chooser.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
594       chooser.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
595       chooser.set_default_response(Gtk::RESPONSE_ACCEPT);
596       chooser.set_do_overwrite_confirmation();
597       chooser.set_current_name (File::sanify(d_armyset->getName ()) +
598                                 ARMYSET_EXT);
599 
600       chooser.show_all();
601       int res = chooser.run();
602 
603       if (res == Gtk::RESPONSE_ACCEPT)
604         {
605           Glib::ustring filename = chooser.get_filename();
606           Glib::ustring old_filename = current_save_filename;
607           guint32 old_id = d_armyset->getId ();
608           d_armyset->setId(Armysetlist::getNextAvailableId(old_id));
609 
610           ret = save_current_armyset_file(filename);
611           if (ret == false)
612             {
613               current_save_filename = old_filename;
614               d_armyset->setId(old_id);
615             }
616           else
617             {
618               save_armyset_menuitem->set_sensitive (true);
619               needs_saving = false;
620               d_armyset->created (filename);
621               Glib::ustring dir =
622                 File::add_slash_if_necessary (File::get_dirname (filename));
623               if (dir == File::getSetDir(ARMYSET_EXT, false) ||
624                   dir == File::getSetDir(ARMYSET_EXT, true))
625                 {
626                   //if we saved it to a standard place, update the list
627                   Armysetlist::getInstance()->add (Armyset::copy (d_armyset),
628                                                    filename);
629                   armyset_saved.emit(d_armyset->getId());
630                 }
631               refresh_armies ();
632               update_army_panel ();
633               update_window_title();
634             }
635         }
636       chooser.hide ();
637       if (res == Gtk::RESPONSE_CANCEL)
638         break;
639       if (ret == true)
640         break;
641     }
642   return ret;
643 }
644 
save_current_armyset_file(Glib::ustring filename)645 bool ArmySetWindow::save_current_armyset_file (Glib::ustring filename)
646 {
647   current_save_filename = filename;
648   if (current_save_filename.empty())
649     current_save_filename = d_armyset->getConfigurationFile(true);
650 
651   sync_armies ();
652 
653   bool ok = d_armyset->save(current_save_filename, Armyset::file_extension);
654   if (ok)
655     {
656       if (Armysetlist::getInstance()->reload(d_armyset->getId()))
657         refresh_armies();
658       update_army_panel ();
659       needs_saving = false;
660       update_window_title();
661       armyset_saved.emit(d_armyset->getId());
662     }
663   else
664     {
665       Glib::ustring errmsg = Glib::strerror(errno);
666       Glib::ustring msg = _("Error!  Army Set could not be saved.");
667       msg += "\n" + current_save_filename + "\n" + errmsg;
668       TimedMessageDialog dialog(*window, msg, 0);
669       dialog.run_and_hide();
670     }
671   return ok;
672 }
673 
on_save_armyset_activated()674 void ArmySetWindow::on_save_armyset_activated()
675 {
676   if (check_save_valid (true))
677     save_current_armyset_file ();
678 }
679 
on_edit_ship_picture_activated()680 void ArmySetWindow::on_edit_ship_picture_activated()
681 {
682   Glib::ustring imgname = d_armyset->getShipImageName();
683   MaskedImageEditorDialog d(*window, imgname,
684                             d_armyset->getShipPic (),
685                             d_armyset->getShipMask (),
686                             EDITOR_DIALOG_TILE_PIC_FONTSIZE_MULTIPLE);
687   d.set_title(_("Select a Ship image"));
688   int response = d.run();
689   if (response == Gtk::RESPONSE_ACCEPT && d.get_filename() != "")
690     {
691       Glib::ustring newname = "";
692       bool success = false;
693       if (imgname.empty () == true)
694         success =
695           d_armyset->addFileInCfgFile( d.get_filename(), newname);
696       else
697         success =
698           d_armyset->replaceFileInCfgFile(imgname, d.get_filename(), newname);
699       if (success)
700         {
701           d_armyset->setShipImageName(newname);
702           d_armyset->instantiateShipImage ();
703           needs_saving = true;
704           update_window_title();
705         }
706       else
707         show_add_file_error(d_armyset, *d.get_dialog(), d.get_filename ());
708     }
709   else if (response == Gtk::RESPONSE_REJECT)
710     {
711       if (d_armyset->removeFileInCfgFile(imgname))
712         {
713           needs_saving = true;
714           update_window_title();
715           d_armyset->uninstantiateSameNamedImages (imgname);
716         }
717       else
718         show_remove_file_error(d_armyset, *d.get_dialog(), imgname);
719     }
720 }
721 
on_edit_standard_picture_activated()722 void ArmySetWindow::on_edit_standard_picture_activated()
723 {
724   Glib::ustring imgname = d_armyset->getStandardImageName();
725   MaskedImageEditorDialog d(*window, imgname,
726                             d_armyset->getStandardPic (),
727                             d_armyset->getStandardMask (),
728                             EDITOR_DIALOG_TILE_PIC_FONTSIZE_MULTIPLE);
729   d.set_title(_("Select a Hero Flag image"));
730   int response = d.run();
731   if (response == Gtk::RESPONSE_ACCEPT && d.get_filename() != "")
732     {
733       Glib::ustring newname = "";
734       bool success = false;
735       if (imgname.empty () == true)
736         success = d_armyset->addFileInCfgFile(d.get_filename(), newname);
737       else
738         success =
739           d_armyset->replaceFileInCfgFile(imgname, d.get_filename(), newname);
740       if (success)
741         {
742           d_armyset->setStandardImageName(newname);
743           d_armyset->instantiateStandardImage ();
744           needs_saving = true;
745           update_window_title();
746         }
747       else
748         show_add_file_error(d_armyset, *d.get_dialog(), d.get_filename ());
749     }
750   else if (response == Gtk::RESPONSE_REJECT)
751     {
752       if (d_armyset->removeFileInCfgFile(imgname))
753         {
754           needs_saving = true;
755           update_window_title();
756           d_armyset->uninstantiateSameNamedImages (imgname);
757         }
758       else
759         show_remove_file_error(d_armyset, *d.get_dialog(), imgname);
760     }
761 }
762 
on_edit_bag_picture_activated()763 void ArmySetWindow::on_edit_bag_picture_activated()
764 {
765   Glib::ustring imgname = d_armyset->getBagImageName();
766   std::vector<PixMask *> frames;
767   if (imgname.empty () == false)
768     frames.push_back (d_armyset->getBagPic ());
769   ImageEditorDialog d(*window, imgname, 1, frames,
770                       EDITOR_DIALOG_TILE_PIC_FONTSIZE_MULTIPLE * 0.5);
771   d.set_title(_("Select a Bag image"));
772   int response = d.run();
773   if (response == Gtk::RESPONSE_ACCEPT && d.get_filename() != "")
774     {
775       Glib::ustring newname = "";
776       bool success = false;
777       if (imgname.empty () == true)
778         success = d_armyset->addFileInCfgFile(d.get_filename(), newname);
779       else
780         success =
781           d_armyset->replaceFileInCfgFile(imgname, d.get_filename(), newname);
782       if (success)
783         {
784           d_armyset->setBagImageName(newname);
785           d_armyset->instantiateBagImage ();
786           needs_saving = true;
787           update_window_title();
788         }
789       else
790         show_add_file_error(d_armyset, *d.get_dialog(), d.get_filename ());
791     }
792   else if (response == Gtk::RESPONSE_REJECT)
793     {
794       if (d_armyset->removeFileInCfgFile(imgname))
795         {
796           needs_saving = true;
797           update_window_title();
798           d_armyset->uninstantiateSameNamedImages (imgname);
799         }
800       else
801         show_remove_file_error(d_armyset, *d.get_dialog(), imgname);
802     }
803 }
804 
on_edit_armyset_info_activated()805 void ArmySetWindow::on_edit_armyset_info_activated()
806 {
807   ArmySetInfoDialog d(*window, d_armyset);
808   bool changed = d.run();
809   if (changed)
810     {
811       needs_saving = true;
812       update_window_title();
813     }
814 }
815 
on_help_about_activated()816 void ArmySetWindow::on_help_about_activated()
817 {
818   Gtk::AboutDialog* dialog;
819 
820   Glib::RefPtr<Gtk::Builder> xml
821     = Gtk::Builder::create_from_file(File::getGladeFile("about-dialog.ui"));
822 
823   xml->get_widget("dialog", dialog);
824   dialog->set_transient_for(*window);
825   dialog->set_icon_from_file(File::getVariousFile("castle_icon.png"));
826 
827   dialog->set_version(PACKAGE_VERSION);
828   dialog->set_logo(ImageCache::loadMiscImage("castle_icon.png")->to_pixbuf());
829   dialog->show_all();
830   dialog->run();
831   delete dialog;
832 
833   return;
834 }
835 
addArmyType(guint32 army_type)836 void ArmySetWindow::addArmyType(guint32 army_type)
837 {
838   ArmyProto *a;
839   //go get army_type in d_armyset
840   a = d_armyset->lookupArmyByType(army_type);
841   Gtk::TreeIter i = armies_list->append();
842   (*i)[armies_columns.name] = a->getName();
843   (*i)[armies_columns.army] = a;
844 }
845 
on_army_selected()846 void ArmySetWindow::on_army_selected()
847 {
848   if (inhibit_updates)
849     return;
850   update_armyset_buttons();
851   update_army_panel();
852   armies_treeview->queue_draw();
853   if (inhibit_scrolldown == false)
854     {
855       while (g_main_context_iteration(NULL, FALSE)); //doEvents
856       armies_scrolledwindow->get_vadjustment()->set_value
857         (armies_scrolledwindow->get_vadjustment()->get_upper());
858     }
859   inhibit_scrolldown = true;
860 }
861 
fill_army_image(Gtk::Button * button,Gtk::Image * image,Shield::Colour c,ArmyProto * army)862 void ArmySetWindow::fill_army_image(Gtk::Button *button, Gtk::Image *image, Shield::Colour c, ArmyProto *army)
863 {
864   Glib::ustring imgname = army->getImageName(c);
865   if (imgname.empty () == false)
866     {
867       Gdk::RGBA colour = Shieldsetlist::getInstance()->getColor(1, c);
868       PixMask *p =
869         ImageCache::applyMask(army->getImage(c), army->getMask(c), colour);
870       double ratio = EDITOR_DIALOG_TILE_PIC_FONTSIZE_MULTIPLE;
871       int font_size = FontSize::getInstance()->get_height ();
872       double new_height = font_size * ratio;
873       int new_width =
874         ImageCache::calculate_width_from_adjusted_height (p, new_height);
875       PixMask::scale (p, new_width, new_height);
876       image->property_pixbuf() = p->to_pixbuf();
877       delete p;
878       button->set_label(imgname);
879     }
880   else
881     {
882       button->set_label(_("No image set"));
883       image->clear();
884     }
885 }
886 
fill_army_images(ArmyProto * army)887 void ArmySetWindow::fill_army_images (ArmyProto *army)
888 {
889   fill_army_image(white_image_button, white_image, Shield::WHITE, army);
890   fill_army_image(green_image_button, green_image, Shield::GREEN, army);
891   fill_army_image(yellow_image_button, yellow_image, Shield::YELLOW, army);
892   fill_army_image(light_blue_image_button, light_blue_image,
893                   Shield::LIGHT_BLUE, army);
894   fill_army_image(red_image_button, red_image, Shield::RED, army);
895   fill_army_image(dark_blue_image_button, dark_blue_image, Shield::DARK_BLUE,
896                   army);
897   fill_army_image(orange_image_button, orange_image, Shield::ORANGE, army);
898   fill_army_image(black_image_button, black_image, Shield::BLACK, army);
899   fill_army_image(neutral_image_button, neutral_image, Shield::NEUTRAL, army);
900 }
901 
fill_army_info(ArmyProto * army)902 void ArmySetWindow::fill_army_info(ArmyProto *army)
903 {
904   fill_army_images (army);
905   name_entry->set_text(army->getName());
906   description_textview->get_buffer()->set_text(army->getDescription());
907   double turns = army->getProduction();
908   production_spinbutton->set_value(turns);
909   cost_spinbutton->set_value(army->getProductionCost());
910   new_cost_spinbutton->set_value(army->getNewProductionCost());
911   upkeep_spinbutton->set_value(army->getUpkeep());
912   strength_spinbutton->set_value(army->getStrength());
913   moves_spinbutton->set_value(army->getMaxMoves());
914   exp_spinbutton->set_value(int(army->getXpReward()));
915   hero_combobox->set_active(int(army->getGender()));
916   awardable_switch->set_active(army->getAwardable());
917   defends_ruins_switch->set_active(army->getDefendsRuins());
918   sight_spinbutton->set_value(army->getSight());
919   id_spinbutton->set_value(army->getId());
920 
921   guint32 bonus = army->getMoveBonus();
922   can_fly_switch->set_active (bonus ==
923 				   (Tile::GRASS | Tile::WATER |
924 				    Tile::FOREST | Tile::HILLS |
925 				    Tile::MOUNTAIN | Tile::SWAMP));
926   if (can_fly_switch->get_active() == false)
927     {
928       move_forests_switch->set_active
929 	((bonus & Tile::FOREST) == Tile::FOREST);
930       move_marshes_switch->set_active
931 	((bonus & Tile::SWAMP) == Tile::SWAMP);
932       move_hills_switch->set_active
933 	((bonus & Tile::HILLS) == Tile::HILLS);
934       move_mountains_switch->set_active
935 	((bonus & Tile::MOUNTAIN) == Tile::MOUNTAIN);
936     }
937   else
938     {
939       move_forests_switch->set_active(false);
940       move_marshes_switch->set_active(false);
941       move_hills_switch->set_active(false);
942       move_mountains_switch->set_active(false);
943     }
944   bonus = army->getArmyBonus();
945   add1strinopen_switch->set_active
946     ((bonus & Army::ADD1STRINOPEN) == Army::ADD1STRINOPEN);
947   add2strinopen_switch->set_active
948     ((bonus & Army::ADD2STRINOPEN) == Army::ADD2STRINOPEN);
949   add1strinforest_switch->set_active
950     ((bonus & Army::ADD1STRINFOREST) == Army::ADD1STRINFOREST);
951   add1strinhills_switch->set_active
952     ((bonus & Army::ADD1STRINHILLS) == Army::ADD1STRINHILLS);
953   add1strincity_switch->set_active
954     ((bonus & Army::ADD1STRINCITY) == Army::ADD1STRINCITY);
955   add2strincity_switch->set_active
956     ((bonus & Army::ADD2STRINCITY) == Army::ADD2STRINCITY);
957   add1stackinhills_switch->set_active
958     ((bonus & Army::ADD1STACKINHILLS) == Army::ADD1STACKINHILLS);
959   suballcitybonus_switch->set_active
960     ((bonus & Army::SUBALLCITYBONUS) == Army::SUBALLCITYBONUS);
961   sub1enemystack_switch->set_active
962     ((bonus & Army::SUB1ENEMYSTACK) == Army::SUB1ENEMYSTACK);
963   add1stack_switch->set_active
964     ((bonus & Army::ADD1STACK) == Army::ADD1STACK);
965   add2stack_switch->set_active
966     ((bonus & Army::ADD2STACK) == Army::ADD2STACK);
967   suballnonherobonus_switch->set_active
968     ((bonus & Army::SUBALLNONHEROBONUS) == Army::SUBALLNONHEROBONUS);
969   suballherobonus_switch->set_active
970     ((bonus & Army::SUBALLHEROBONUS) == Army::SUBALLHEROBONUS);
971 }
972 
on_name_changed()973 void ArmySetWindow::on_name_changed()
974 {
975   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
976   Gtk::TreeModel::iterator iterrow = selection->get_selected();
977 
978   if (iterrow)
979     {
980       Gtk::TreeModel::Row row = *iterrow;
981       ArmyProto *a = row[armies_columns.army];
982       a->setName(name_entry->get_text());
983       row[armies_columns.name] = name_entry->get_text();
984       if (inhibit_needs_saving == false)
985         {
986           needs_saving = true;
987           update_window_title();
988         }
989     }
990 }
991 
on_description_changed()992 void ArmySetWindow::on_description_changed()
993 {
994   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
995   Gtk::TreeModel::iterator iterrow = selection->get_selected();
996 
997   if (iterrow)
998     {
999       Gtk::TreeModel::Row row = *iterrow;
1000       ArmyProto *a = row[armies_columns.army];
1001       a->setDescription(description_textview->get_buffer()->get_text());
1002       if (inhibit_needs_saving == false)
1003         {
1004           needs_saving = true;
1005           update_window_title();
1006         }
1007     }
1008 }
1009 
instantiateOthers(ArmyProto * a,Shield::Colour c,Glib::ustring filename)1010 void ArmySetWindow::instantiateOthers (ArmyProto *a, Shield::Colour c,
1011                                        Glib::ustring filename)
1012 {
1013   if (a->getImageName (c).empty () == true)
1014     return;
1015   //what a hassle.  an army can reuse the same file many times
1016   for (unsigned int i = Shield::WHITE; i <= Shield::NEUTRAL; i++)
1017     {
1018       Shield::Colour col = Shield::Colour(i);
1019       if (col == c)
1020         continue;
1021       if (a->getImageName (c) == a->getImageName (col))
1022         {
1023           a->setImageName(col, filename);
1024           a->instantiateImage (d_armyset->getConfigurationFile (),
1025                                d_armyset->getTileSize (), col);
1026         }
1027     }
1028 }
1029 
on_image_changed(Shield::Colour c)1030 void ArmySetWindow::on_image_changed(Shield::Colour c)
1031 {
1032   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1033   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1034 
1035   if (iterrow)
1036     {
1037       Gtk::TreeModel::Row row = *iterrow;
1038       ArmyProto *a = row[armies_columns.army];
1039       Glib::ustring imgname = a->getImageName(c);
1040       MaskedImageEditorDialog d(*window, imgname,
1041                                 a->getImage (c), a->getMask (c),
1042                                 EDITOR_DIALOG_TILE_PIC_FONTSIZE_MULTIPLE);
1043       d.set_title(String::ucompose(_("Select a %1 Army image"),
1044                                    Shield::colourToFriendlyName(c)));
1045       int response = d.run();
1046       if (response == Gtk::RESPONSE_ACCEPT && d.get_filename() != "")
1047         {
1048           Glib::ustring newname = "";
1049           bool success = false;
1050           if (imgname.empty () == true)
1051             success =
1052               d_armyset->addFileInCfgFile(d.get_filename(), newname);
1053           else
1054             success =
1055               d_armyset->replaceFileInCfgFile(imgname, d.get_filename(),
1056                                               newname);
1057           if (success)
1058             {
1059               instantiateOthers (a, c, newname);
1060               a->setImageName(c, newname);
1061               a->instantiateImage (d_armyset->getConfigurationFile (),
1062                                    d_armyset->getTileSize (), c);
1063               fill_army_images (a);
1064 
1065               if (inhibit_needs_saving == false)
1066                 {
1067                   needs_saving = true;
1068                   update_window_title();
1069                 }
1070             }
1071           else
1072             show_add_file_error(d_armyset, *d.get_dialog(), d.get_filename ());
1073         }
1074       else if (response == Gtk::RESPONSE_REJECT)
1075         {
1076           if (d_armyset->removeFileInCfgFile(imgname))
1077             {
1078               needs_saving = true;
1079               update_window_title();
1080               d_armyset->uninstantiateSameNamedImages (imgname);
1081               fill_army_images (a);
1082             }
1083         }
1084     }
1085 }
1086 
on_production_text_changed()1087 void ArmySetWindow::on_production_text_changed()
1088 {
1089   production_spinbutton->set_value(atoi(production_spinbutton->get_text().c_str()));
1090   on_production_changed();
1091 }
1092 
on_production_changed()1093 void ArmySetWindow::on_production_changed()
1094 {
1095   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1096   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1097 
1098   if (iterrow)
1099     {
1100       Gtk::TreeModel::Row row = *iterrow;
1101       ArmyProto *a = row[armies_columns.army];
1102       if (production_spinbutton->get_value() <
1103 	  MIN_PRODUCTION_TURNS_FOR_ARMY_UNITS)
1104 	production_spinbutton->set_value(MIN_PRODUCTION_TURNS_FOR_ARMY_UNITS);
1105       else if (production_spinbutton->get_value() >
1106 	       MAX_PRODUCTION_TURNS_FOR_ARMY_UNITS)
1107 	production_spinbutton->set_value(MAX_PRODUCTION_TURNS_FOR_ARMY_UNITS);
1108       else
1109 	a->setProduction(int(production_spinbutton->get_value()));
1110       if (inhibit_needs_saving == false)
1111         {
1112           needs_saving = true;
1113           update_window_title();
1114         }
1115     }
1116 }
1117 
on_cost_text_changed()1118 void ArmySetWindow::on_cost_text_changed()
1119 {
1120   cost_spinbutton->set_value(atoi(cost_spinbutton->get_text().c_str()));
1121   on_cost_changed();
1122 }
1123 
on_cost_changed()1124 void ArmySetWindow::on_cost_changed()
1125 {
1126   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1127   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1128 
1129   if (iterrow)
1130     {
1131       Gtk::TreeModel::Row row = *iterrow;
1132       ArmyProto *a = row[armies_columns.army];
1133       if (cost_spinbutton->get_value() < MIN_COST_FOR_ARMY_UNITS)
1134 	cost_spinbutton->set_value(MIN_COST_FOR_ARMY_UNITS);
1135       else if (strength_spinbutton->get_value() > MAX_COST_FOR_ARMY_UNITS)
1136 	cost_spinbutton->set_value(MAX_COST_FOR_ARMY_UNITS);
1137       else
1138 	a->setProductionCost(int(cost_spinbutton->get_value()));
1139       if (inhibit_needs_saving == false)
1140         {
1141           needs_saving = true;
1142           update_window_title();
1143         }
1144     }
1145 }
1146 
on_new_cost_text_changed()1147 void ArmySetWindow::on_new_cost_text_changed()
1148 {
1149   new_cost_spinbutton->set_value(atoi(new_cost_spinbutton->get_text().c_str()));
1150   on_new_cost_changed();
1151 }
1152 
on_new_cost_changed()1153 void ArmySetWindow::on_new_cost_changed()
1154 {
1155   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1156   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1157 
1158   if (iterrow)
1159     {
1160       Gtk::TreeModel::Row row = *iterrow;
1161       ArmyProto *a = row[armies_columns.army];
1162       a->setNewProductionCost(int(new_cost_spinbutton->get_value()));
1163       if (inhibit_needs_saving == false)
1164         {
1165           needs_saving = true;
1166           update_window_title();
1167         }
1168     }
1169 }
1170 
on_upkeep_text_changed()1171 void ArmySetWindow::on_upkeep_text_changed()
1172 {
1173   upkeep_spinbutton->set_value(atoi(upkeep_spinbutton->get_text().c_str()));
1174   on_upkeep_changed();
1175 }
1176 
on_upkeep_changed()1177 void ArmySetWindow::on_upkeep_changed()
1178 {
1179   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1180   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1181 
1182   if (iterrow)
1183     {
1184       Gtk::TreeModel::Row row = *iterrow;
1185       ArmyProto  *a = row[armies_columns.army];
1186       if (upkeep_spinbutton->get_value() < MIN_UPKEEP_FOR_ARMY_UNITS)
1187 	upkeep_spinbutton->set_value(MIN_UPKEEP_FOR_ARMY_UNITS);
1188       else if (upkeep_spinbutton->get_value() > MAX_UPKEEP_FOR_ARMY_UNITS)
1189 	upkeep_spinbutton->set_value(MAX_UPKEEP_FOR_ARMY_UNITS);
1190       else
1191 	a->setUpkeep(int(upkeep_spinbutton->get_value()));
1192       if (inhibit_needs_saving == false)
1193         {
1194           needs_saving = true;
1195           update_window_title();
1196         }
1197     }
1198 }
1199 
on_strength_text_changed()1200 void ArmySetWindow::on_strength_text_changed()
1201 {
1202   strength_spinbutton->set_value(atoi(strength_spinbutton->get_text().c_str()));
1203   on_strength_changed();
1204 }
1205 
on_strength_changed()1206 void ArmySetWindow::on_strength_changed()
1207 {
1208   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1209   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1210 
1211   if (iterrow)
1212     {
1213       Gtk::TreeModel::Row row = *iterrow;
1214       ArmyProto *a = row[armies_columns.army];
1215       if (strength_spinbutton->get_value() < MIN_STRENGTH_FOR_ARMY_UNITS)
1216 	strength_spinbutton->set_value(MIN_STRENGTH_FOR_ARMY_UNITS);
1217       else if (strength_spinbutton->get_value() > MAX_STRENGTH_FOR_ARMY_UNITS)
1218 	strength_spinbutton->set_value(MAX_STRENGTH_FOR_ARMY_UNITS);
1219       else
1220 	a->setStrength(int(strength_spinbutton->get_value()));
1221       if (inhibit_needs_saving == false)
1222         {
1223           needs_saving = true;
1224           update_window_title();
1225         }
1226     }
1227 }
1228 
on_moves_text_changed()1229 void ArmySetWindow::on_moves_text_changed()
1230 {
1231   moves_spinbutton->set_value(atoi(moves_spinbutton->get_text().c_str()));
1232   on_moves_changed();
1233 }
1234 
on_moves_changed()1235 void ArmySetWindow::on_moves_changed()
1236 {
1237   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1238   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1239 
1240   if (iterrow)
1241     {
1242       Gtk::TreeModel::Row row = *iterrow;
1243       ArmyProto *a = row[armies_columns.army];
1244       if (moves_spinbutton->get_value() < MIN_MOVES_FOR_ARMY_UNITS)
1245 	moves_spinbutton->set_value(MIN_MOVES_FOR_ARMY_UNITS);
1246       else if (moves_spinbutton->get_value() > MAX_MOVES_FOR_ARMY_UNITS)
1247 	moves_spinbutton->set_value(MAX_MOVES_FOR_ARMY_UNITS);
1248       else
1249 	a->setMaxMoves(int(moves_spinbutton->get_value()));
1250       if (inhibit_needs_saving == false)
1251         {
1252           needs_saving = true;
1253           update_window_title();
1254         }
1255     }
1256 }
1257 
on_exp_text_changed()1258 void ArmySetWindow::on_exp_text_changed()
1259 {
1260   exp_spinbutton->set_value(atoi(exp_spinbutton->get_text().c_str()));
1261   on_exp_changed();
1262 }
1263 
on_exp_changed()1264 void ArmySetWindow::on_exp_changed()
1265 {
1266   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1267   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1268 
1269   if (iterrow)
1270     {
1271       Gtk::TreeModel::Row row = *iterrow;
1272       ArmyProto *a = row[armies_columns.army];
1273       a->setXpReward(int(exp_spinbutton->get_value()));
1274       if (inhibit_needs_saving == false)
1275         {
1276           needs_saving = true;
1277           update_window_title();
1278         }
1279     }
1280 }
1281 
on_sight_text_changed()1282 void ArmySetWindow::on_sight_text_changed()
1283 {
1284   sight_spinbutton->set_value(atoi(sight_spinbutton->get_text().c_str()));
1285   on_sight_changed();
1286 }
1287 
on_sight_changed()1288 void ArmySetWindow::on_sight_changed()
1289 {
1290   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1291   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1292 
1293   if (iterrow)
1294     {
1295       Gtk::TreeModel::Row row = *iterrow;
1296       ArmyProto *a = row[armies_columns.army];
1297       a->setSight(int(sight_spinbutton->get_value()));
1298       if (inhibit_needs_saving == false)
1299         {
1300           needs_saving = true;
1301           update_window_title();
1302         }
1303     }
1304 }
1305 
on_id_text_changed()1306 void ArmySetWindow::on_id_text_changed()
1307 {
1308   id_spinbutton->set_value(atoi(id_spinbutton->get_text().c_str()));
1309   on_sight_changed();
1310 }
1311 
on_id_changed()1312 void ArmySetWindow::on_id_changed()
1313 {
1314   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1315   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1316 
1317   if (iterrow)
1318     {
1319       Gtk::TreeModel::Row row = *iterrow;
1320       ArmyProto *a = row[armies_columns.army];
1321       a->setId(int(id_spinbutton->get_value()));
1322       if (inhibit_needs_saving == false)
1323         {
1324           needs_saving = true;
1325           update_window_title();
1326         }
1327     }
1328 }
1329 
on_hero_combobox_changed()1330 void ArmySetWindow::on_hero_combobox_changed()
1331 {
1332   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1333   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1334 
1335   if (iterrow)
1336     {
1337       Gtk::TreeModel::Row row = *iterrow;
1338       ArmyProto *a = row[armies_columns.army];
1339       a->setGender(Hero::Gender(hero_combobox->get_active_row_number()));
1340       if (inhibit_needs_saving == false)
1341         {
1342           needs_saving = true;
1343           update_window_title();
1344         }
1345     }
1346 }
1347 
on_awardable_toggled()1348 void ArmySetWindow::on_awardable_toggled()
1349 {
1350   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1351   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1352 
1353   if (iterrow)
1354     {
1355       Gtk::TreeModel::Row row = *iterrow;
1356       ArmyProto *a = row[armies_columns.army];
1357       a->setAwardable(awardable_switch->get_active());
1358       if (inhibit_needs_saving == false)
1359         {
1360           needs_saving = true;
1361           update_window_title();
1362         }
1363     }
1364 }
1365 
on_defends_ruins_toggled()1366 void ArmySetWindow::on_defends_ruins_toggled()
1367 {
1368   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1369   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1370 
1371   if (iterrow)
1372     {
1373       Gtk::TreeModel::Row row = *iterrow;
1374       ArmyProto *a = row[armies_columns.army];
1375       a->setDefendsRuins(defends_ruins_switch->get_active());
1376       if (inhibit_needs_saving == false)
1377         {
1378           needs_saving = true;
1379           update_window_title();
1380         }
1381     }
1382 }
1383 
on_movebonus_toggled(Gtk::Switch * button,guint32 val)1384 void ArmySetWindow::on_movebonus_toggled(Gtk::Switch *button, guint32 val)
1385 {
1386   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1387   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1388 
1389   if (iterrow)
1390     {
1391       Gtk::TreeModel::Row row = *iterrow;
1392       ArmyProto *a = row[armies_columns.army];
1393       guint32 bonus = a->getMoveBonus();
1394       if (button->get_active() == true)
1395 	  bonus |= val;
1396       else
1397 	{
1398 	  if (bonus & val)
1399 	    bonus ^= val;
1400 	}
1401       a->setMoveBonus(bonus);
1402       if (inhibit_needs_saving == false)
1403         {
1404           needs_saving = true;
1405           update_window_title();
1406         }
1407     }
1408 }
1409 
on_armybonus_toggled(Gtk::Switch * button,guint32 val)1410 void ArmySetWindow::on_armybonus_toggled(Gtk::Switch *button, guint32 val)
1411 {
1412   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1413   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1414 
1415   if (iterrow)
1416     {
1417       Gtk::TreeModel::Row row = *iterrow;
1418       ArmyProto *a = row[armies_columns.army];
1419       guint32 bonus = a->getArmyBonus();
1420       if (button->get_active() == true)
1421 	bonus |= val;
1422       else
1423 	{
1424 	  if (bonus & val)
1425 	    bonus ^= val;
1426 	}
1427       a->setArmyBonus(bonus);
1428       if (inhibit_needs_saving == false)
1429         {
1430           needs_saving = true;
1431           update_window_title();
1432         }
1433     }
1434 }
1435 
on_add_army_clicked()1436 void ArmySetWindow::on_add_army_clicked()
1437 {
1438   inhibit_scrolldown=false;
1439   //add a new empty army to the armyset
1440   ArmyProto *a = new ArmyProto();
1441   //add it to the treeview
1442   Gtk::TreeIter i = armies_list->append();
1443   a->setName(_("Untitled"));
1444   (*i)[armies_columns.name] = a->getName();
1445   (*i)[armies_columns.army] = a;
1446   if (d_armyset->empty() == true)
1447     a->setId(0);
1448   else
1449     a->setId(d_armyset->getMaxId() + 1);
1450   d_armyset->push_back(a);
1451   needs_saving = true;
1452   update_window_title();
1453   if (d_armyset->empty() == false)
1454     armies_treeview->get_selection()->select(i);
1455 }
1456 
on_remove_army_clicked()1457 void ArmySetWindow::on_remove_army_clicked()
1458 {
1459   //erase the selected row from the treeview
1460   //remove the army from the armyset
1461   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1462   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1463 
1464   if (iterrow)
1465     {
1466       Gtk::TreeModel::Row row = *iterrow;
1467       ArmyProto *a = row[armies_columns.army];
1468       armies_list->erase(iterrow);
1469       d_armyset->remove(a);
1470       needs_saving = true;
1471       update_window_title();
1472     }
1473 }
1474 
load_armyset(Glib::ustring filename)1475 bool ArmySetWindow::load_armyset(Glib::ustring filename)
1476 {
1477   inhibit_scrolldown=true;
1478   Glib::ustring old_current_save_filename = current_save_filename;
1479   current_save_filename = filename;
1480 
1481   bool unsupported_version;
1482   Armyset *armyset = Armyset::create(current_save_filename, unsupported_version);
1483   if (armyset == NULL)
1484     {
1485       Glib::ustring msg;
1486       if (unsupported_version)
1487         msg = _("Error!  The version of Army Set is unsupported.");
1488       else
1489         msg = _("Error!  Army Set could not be loaded.");
1490       TimedMessageDialog dialog(*window, msg, 0);
1491       current_save_filename = old_current_save_filename;
1492       dialog.run_and_hide();
1493       return false;
1494     }
1495   armies_list->clear();
1496   if (d_armyset)
1497     delete d_armyset;
1498   d_armyset = armyset;
1499   d_armyset->setLoadTemporaryFile ();
1500 
1501   bool broken = false;
1502   d_armyset->instantiateImages(false, broken);
1503   if (broken)
1504     {
1505       delete d_armyset;
1506       d_armyset = NULL;
1507       TimedMessageDialog td(*window, _("Couldn't load Army Set images."), 0);
1508       td.run_and_hide();
1509       return false;
1510     }
1511   for (Armyset::iterator i = d_armyset->begin(); i != d_armyset->end(); ++i)
1512     addArmyType((*i)->getId());
1513   if (d_armyset->empty() == false)
1514     {
1515       Gtk::TreeModel::Row row;
1516       row = armies_treeview->get_model()->children()[0];
1517       if(row)
1518 	armies_treeview->get_selection()->select(row);
1519     }
1520   save_armyset_menuitem->set_sensitive (true);
1521   needs_saving = false;
1522   update_window_title();
1523   inhibit_scrolldown=false;
1524   return true;
1525 }
1526 
quit()1527 bool ArmySetWindow::quit()
1528 {
1529   if (needs_saving)
1530     {
1531       EditorQuitDialog d (*window);
1532       int response = d.run_and_hide();
1533 
1534       if (response == Gtk::RESPONSE_CANCEL) // we don't want to new
1535         return false;
1536 
1537       else if (response == Gtk::RESPONSE_ACCEPT) // save it
1538         {
1539           bool saved = false;
1540           bool existing = d_armyset->getDirectory().empty () == false;
1541           if (existing)
1542             {
1543               if (check_save_valid (true))
1544                 {
1545                   if (save_current_armyset_file ())
1546                     saved = true;
1547                 }
1548               else
1549                 return false;
1550             }
1551           else
1552             {
1553               if (check_save_valid (false))
1554                 saved = save_current_armyset_file_as ();
1555               else
1556                 return false;
1557             }
1558           if (!saved)
1559             return false;
1560         }
1561     }
1562   window->hide ();
1563   if (d_armyset)
1564     delete d_armyset;
1565   return true;
1566 }
1567 
on_window_closed(GdkEventAny *)1568 bool ArmySetWindow::on_window_closed(GdkEventAny*)
1569 {
1570   return !quit();
1571 }
1572 
on_quit_activated()1573 void ArmySetWindow::on_quit_activated()
1574 {
1575   quit();
1576 }
1577 
update_window_title()1578 void ArmySetWindow::update_window_title()
1579 {
1580   Glib::ustring title = "";
1581   if (needs_saving)
1582     title += "*";
1583   title += d_armyset->getName();
1584   title += " - ";
1585   title += _("Army Set Editor");
1586   window->set_title(title);
1587 }
1588 
lookup_button_by_colour(Shield::Colour s)1589 Gtk::Button *ArmySetWindow::lookup_button_by_colour (Shield::Colour s)
1590 {
1591   switch (s)
1592     {
1593     case Shield::WHITE: return white_image_button;
1594     case Shield::GREEN: return green_image_button;
1595     case Shield::YELLOW: return yellow_image_button;
1596     case Shield::DARK_BLUE: return dark_blue_image_button;
1597     case Shield::ORANGE: return orange_image_button;
1598     case Shield::LIGHT_BLUE: return light_blue_image_button;
1599     case Shield::RED: return red_image_button;
1600     case Shield::BLACK: return black_image_button;
1601     case Shield::NEUTRAL: return neutral_image_button;
1602     }
1603   return NULL;
1604 }
1605 
on_make_same_clicked()1606 void ArmySetWindow::on_make_same_clicked()
1607 {
1608   Glib::RefPtr<Gtk::TreeSelection> selection = armies_treeview->get_selection();
1609   Gtk::TreeModel::iterator iterrow = selection->get_selected();
1610   Gtk::TreeModel::Row row = *iterrow;
1611   if (!row)
1612     return;
1613   ArmyProto *a = row[armies_columns.army];
1614   if (!a)
1615     return;
1616   if (a->getImageName(Shield::WHITE).empty())
1617     return;
1618   Glib::ustring in = a->getImageName(Shield::Colour(0));
1619   Glib::ustring white_filename = d_armyset->getFileFromConfigurationFile(in);
1620   if (white_filename.empty () == true)
1621     return;
1622 
1623 
1624   //we have to save the white army image elsewhere
1625   //because it gets blown away in its temporary directory otherwise.
1626   Glib::ustring tmp_dir = File::get_tmp_file();
1627   File::create_dir (tmp_dir);
1628   Glib::ustring wbname = File::get_basename (white_filename, true);
1629   Glib::ustring wdestfile = String::ucompose ("%1/%2", tmp_dir, wbname);
1630 
1631   File::copy (white_filename, wdestfile);
1632   white_filename = wdestfile;
1633 
1634   //get the image for white and then transfer it to the rest.
1635   green_image_button->set_label(white_image_button->get_label());
1636   yellow_image_button->set_label(white_image_button->get_label());
1637   light_blue_image_button->set_label(white_image_button->get_label());
1638   red_image_button->set_label(white_image_button->get_label());
1639   dark_blue_image_button->set_label(white_image_button->get_label());
1640   orange_image_button->set_label(white_image_button->get_label());
1641   black_image_button->set_label(white_image_button->get_label());
1642   neutral_image_button->set_label(white_image_button->get_label());
1643 
1644   Gtk::Image *images[MAX_PLAYERS+1];
1645   images[0] = NULL;
1646   images[1] = green_image;
1647   images[2] = yellow_image;
1648   images[3] = light_blue_image;
1649   images[4] = red_image;
1650   images[5] = dark_blue_image;
1651   images[6] = orange_image;
1652   images[7] = black_image;
1653   images[8] = neutral_image;
1654   for (unsigned int i = Shield::GREEN; i <= Shield::NEUTRAL; i++)
1655     {
1656       Shield::Colour s = Shield::Colour(i);
1657       Glib::ustring imgname = a->getImageName(s);
1658       Glib::ustring newname = "";
1659 
1660       bool success = false;
1661       if (imgname.empty () == true)
1662         success =
1663           d_armyset->addFileInCfgFile(white_filename, newname);
1664       else
1665         success =
1666           d_armyset->replaceFileInCfgFile(imgname, white_filename, newname);
1667       if (success)
1668         {
1669           a->setImageName(s, newname);
1670           bool broken = false;
1671           Gdk::RGBA colour = Shieldsetlist::getInstance()->getColor(1, s);
1672           broken =
1673             a->instantiateImage (d_armyset->getConfigurationFile (),
1674                                  d_armyset->getTileSize (), s);
1675           if (!broken)
1676             {
1677               PixMask *p =
1678                 ImageCache::applyMask(a->getImage(s), a->getMask(s), colour);
1679               double ratio = EDITOR_DIALOG_TILE_PIC_FONTSIZE_MULTIPLE;
1680               int font_size = FontSize::getInstance()->get_height ();
1681               double new_height = font_size * ratio;
1682               int new_width =
1683                 ImageCache::calculate_width_from_adjusted_height (p, new_height);
1684               PixMask::scale (p, new_width, new_height);
1685               images[i]->property_pixbuf() = p->to_pixbuf();
1686               delete p;
1687               Gtk::Button *button = lookup_button_by_colour (s);
1688               if (button)
1689                 button->set_label(a->getImageName (s));
1690             }
1691         }
1692       else
1693         {
1694           show_add_file_error(d_armyset, *window, white_filename);
1695           break;
1696         }
1697     }
1698   File::erase (white_filename);
1699   File::erase_dir (tmp_dir);
1700 }
1701 
show_add_file_error(Armyset * a,Gtk::Window & d,Glib::ustring file)1702 void ArmySetWindow::show_add_file_error(Armyset *a, Gtk::Window &d, Glib::ustring file)
1703 {
1704   Glib::ustring errmsg = Glib::strerror(errno);
1705   Glib::ustring m = String::ucompose(_("Couldn't add %1 to:\n%2\n%3"), file,
1706                                      a->getConfigurationFile(), errmsg);
1707   TimedMessageDialog td(d, m, 0);
1708   td.run_and_hide();
1709 }
1710 
show_remove_file_error(Armyset * a,Gtk::Window & d,Glib::ustring file)1711 void ArmySetWindow::show_remove_file_error(Armyset *a, Gtk::Window &d, Glib::ustring file)
1712 {
1713   Glib::ustring errmsg = Glib::strerror(errno);
1714   Glib::ustring m =
1715     String::ucompose(_("Couldn't remove %1 from:\n%2\n%3"), file,
1716                      a->getConfigurationFile(), errmsg);
1717   TimedMessageDialog td(d, m, 0);
1718   td.run_and_hide();
1719 }
1720 
refresh_armies()1721 void ArmySetWindow::refresh_armies()
1722 {
1723   Armyset::iterator j = d_armyset->begin();
1724   for (Gtk::TreeNodeChildren::iterator i = armies_list->children().begin();
1725        i != armies_list->children().end(); i++, j++)
1726     (*i)[armies_columns.army] = *j;
1727 }
1728 
~ArmySetWindow()1729 ArmySetWindow::~ArmySetWindow()
1730 {
1731   notebook->property_show_tabs () = false;
1732   delete window;
1733 }
1734 
on_tutorial_video_activated()1735 void ArmySetWindow::on_tutorial_video_activated()
1736 {
1737   GError *errs = NULL;
1738   gtk_show_uri(window->get_screen()->gobj(),
1739                "http://vimeo.com/407659798", 0, &errs);
1740   return;
1741 }
1742 
check_discard(Glib::ustring msg)1743 bool ArmySetWindow::check_discard (Glib::ustring msg)
1744 {
1745   if (needs_saving)
1746     {
1747       EditorSaveChangesDialog d (*window, msg);
1748       int response = d.run_and_hide();
1749 
1750       if (response == Gtk::RESPONSE_CANCEL) // we don't want to new
1751         return false;
1752 
1753       else if (response == Gtk::RESPONSE_ACCEPT) // save it
1754         {
1755           if (check_save_valid (true))
1756             {
1757               bool saved = false;
1758               if (d_armyset->getDirectory ().empty () == false)
1759                   saved = save_current_armyset_file_as ();
1760               else
1761                 {
1762                   if (save_current_armyset_file ())
1763                     saved = true;
1764                 }
1765               if (!saved)
1766                 return false;
1767             }
1768           else
1769             return false;
1770         }
1771     }
1772   return true;
1773 }
1774 
check_save_valid(bool existing)1775 bool ArmySetWindow::check_save_valid (bool existing)
1776 {
1777   if (check_name_valid (existing) == false)
1778     return false;
1779 
1780   if (d_armyset->validate () == false)
1781     {
1782       //welp, we don't do it this way with armysets.
1783       //we will have to check each of the players to see if they use this.
1784       if (existing &&
1785           Playerlist::getInstance()->hasArmyset(d_armyset->getId()))
1786         {
1787           Glib::ustring errmsg =
1788             _("Army Set is invalid, and is also one of the current working Army Sets.");
1789           Glib::ustring msg = _("Error!  Army Set could not be saved.");
1790           msg += "\n" + current_save_filename + "\n" + errmsg;
1791           TimedMessageDialog dialog(*window, msg, 0);
1792           dialog.run_and_hide();
1793           return false;
1794         }
1795       else
1796         {
1797           TimedMessageDialog
1798             dialog(*window,
1799                    _("The Army Set is invalid.  Do you want to proceed?"), 0);
1800           dialog.add_cancel_button ();
1801           dialog.run_and_hide();
1802           if (dialog.get_response () == Gtk::RESPONSE_CANCEL)
1803             return false;
1804         }
1805     }
1806   return true;
1807 }
1808 
check_name_valid(bool existing)1809 bool ArmySetWindow::check_name_valid (bool existing)
1810 {
1811   Glib::ustring name = d_armyset->getName ();
1812   Glib::ustring newname = "";
1813   if (existing)
1814     {
1815       Armyset *oldarmyset =
1816         Armysetlist::getInstance ()->get(d_armyset->getId());
1817       if (oldarmyset && oldarmyset->getName () != name)
1818           newname = oldarmyset->getName ();
1819     }
1820 
1821   guint32 num = 0;
1822   Glib::ustring n = String::utrim (String::strip_trailing_numbers (name));
1823   if (n == "")
1824     n = _("Untitled");
1825   if (newname.empty () == true)
1826     newname =
1827       Armysetlist::getInstance()->findFreeName(n, 100, num,
1828                                                d_armyset->getTileSize ());
1829   if (name == "")
1830     {
1831       if (newname.empty() == true)
1832         {
1833           Glib::ustring msg =
1834             _("The Army Set has an invalid name.\nChange it and save again.");
1835           TimedMessageDialog d(*window, msg, 0);
1836           d.run_and_hide();
1837           on_edit_armyset_info_activated ();
1838           return false;
1839         }
1840       else
1841         {
1842           Glib::ustring msg =
1843             String::ucompose (_("The Army Set has an invalid name.\nChange it to '%1'?"), newname);
1844           TimedMessageDialog d(*window, msg, 0);
1845           d.add_cancel_button ();
1846           d.run_and_hide();
1847           if (d.get_response () == Gtk::RESPONSE_CANCEL)
1848             return false;
1849           d_armyset->setName (newname);
1850         }
1851     }
1852 
1853   //okay the question is whether or not the name is already used.
1854   bool same_name = false;
1855   Glib::ustring file =
1856     Armysetlist::getInstance()->lookupConfigurationFileByName(d_armyset);
1857   if (file == "")
1858     return true;
1859 
1860   Glib::ustring cfgfile = d_armyset->getConfigurationFile(true);
1861 
1862   if (existing) // this means we're doing File->Save
1863     {
1864       if (file == cfgfile)
1865         return true;
1866       same_name = true;
1867     }
1868   else // this means we're doing File->Save As
1869     same_name = true;
1870 
1871   if (same_name)
1872     {
1873       if (newname.empty() == true)
1874         {
1875           Glib::ustring msg =
1876             _("The Army Set has the same name as another one.\nChange it and save again.");
1877           TimedMessageDialog d(*window, msg, 0);
1878           d.run_and_hide();
1879           on_edit_armyset_info_activated ();
1880           return false;
1881         }
1882       else
1883         {
1884           Glib::ustring msg =
1885             String::ucompose (_("The Army Set has the same name as another one.\nChange it to '%1' instead?."), newname);
1886 
1887           TimedMessageDialog d(*window, msg, 0);
1888           d.add_cancel_button ();
1889           d.run_and_hide ();
1890           if (d.get_response () == Gtk::RESPONSE_CANCEL)
1891             return false;
1892           d_armyset->setName (newname);
1893         }
1894     }
1895 
1896   return true;
1897 }
1898 
isValidName()1899 bool ArmySetWindow::isValidName ()
1900 {
1901   Glib::ustring file =
1902     Armysetlist::getInstance()->lookupConfigurationFileByName(d_armyset);
1903   if (file == "")
1904     return true;
1905   if (file == d_armyset->getConfigurationFile (true))
1906     return true;
1907   return false;
1908 }
1909 
on_army_moved()1910 void ArmySetWindow::on_army_moved ()
1911 {
1912   needs_saving = true;
1913   update_window_title ();
1914 }
1915 
1916 /*
1917  some test cases
1918   1. create a new armyset from scratch, save invalid set, close, load it
1919   2. create a new armyset from scratch, save valid set, then switch sets
1920   3. save a copy of the default armyset, and switch sets
1921   4. modify the working armyset so we can see it change in scenario builder
1922   5. modify the working armyset so that it's invalid, try to save
1923   6. try adding an image file that isn't a .png
1924   7. try adding an image file that says it's a .png but is actually random data
1925   8. modify an existing armyset by replacing the scouts image with another
1926   9. modify an existing armyset by removing an army, save it, close, load
1927  10. modify an existing armyset by adding an army, save it, close, load
1928  11. try saving a new armyset that has a same name
1929  12. try saving an existing armyset that has a same name
1930  13. validate an armyset without: a neutral image for pikemen
1931  14. validate an armyset without: a bag image
1932  15. validate an armyset without: a hero's flag image
1933  16. try saving an armyset that has an empty name
1934  17. validate an armyset with a same name
1935  18. validate a armyset with an empty name
1936  19. make a new invalid armyset and quit save it
1937  20. load a writable armyset, modify and quit save it
1938  21. load a writable armyset, make it invalid, and then quit save it
1939  22. try saving an armyset we don't have permission to save
1940  23. try quit-saving an armyset we don't have permission to save
1941  24. create a new armyset, add a bag image, save invalid set, close, load it
1942  25. load a writable armyset, remove bag image, quit-save it.  load it
1943  26. create a new armyset, add hero flag, save invalid set, close, load it
1944  27. load a writable armyset, remove hero flag, quit-save it.  load it
1945  28. create a new armyset, add ship picture, save invalid set, close, load it
1946  29. load a writable armyset, remove ship picture, quit-save it.  load it
1947 */
1948