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